How do you mitigate cross-site scripting in an app an AI builder wrote? Apply 4 defenses in order: encode user text for the place it is output, keep it out of sinks that turn a string into code (innerHTML, dangerouslySetInnerHTML, v-html) or sanitize it first, allow only safe URL schemes in links, and add a Content-Security-Policy as the net.
How to mitigate cross-site scripting: four defenses in order
Cross-site scripting is mitigated with 4 defenses in this order: encode untrusted text for the context it is output in, keep it out of sinks that turn strings into code, allow only safe URL schemes in links, and add a Content-Security-Policy and HttpOnly cookies as nets. Frameworks do the first until you switch it off.
The rule under all four fits in one sentence: text that came from a user, a URL, a database row or a model is data, and it has to reach the page as text, never as markup or script. That rule is the browser half of web app security, and every XSS mitigation below is a way of keeping it.
| # | Defense | What it stops | What it does not stop | Where it lives |
|---|---|---|---|---|
| 1 | Output encoding for the context (HTML, attribute, URL, JavaScript, CSS) | User text being parsed as markup or script | HTML you have chosen to render as HTML | The framework’s default escaping (JSX, Vue templates, Django templates); an encoding library where the framework stops |
| 2 | Staying out of dangerous sinks, and sanitizing with an allow-list when rich content must render | Markup and handlers inside HTML you render on purpose | Content changed after it was sanitized | textContent in place of innerHTML; an allow-list sanitizer such as DOMPurify before any raw-HTML feature |
| 3 | Checking a URL before it becomes an href or src | javascript: links and other unexpected schemes | Bugs in how the rest of the page is rendered | The component or server code that builds the link |
| 4 | The nets: a Content-Security-Policy without unsafe-inline, HttpOnly session cookies, Trusted Types | Injected inline script running; script reading the session cookie | The bug itself; script acting as the signed-in user | Response headers, cookie settings, the require-trusted-types-for CSP directive |
This order for cross-site scripting mitigation comes from OWASP’s XSS prevention cheat sheet, which calls XSS attacks “serious”, walks through framework security, output encoding, HTML sanitization and safe sinks first, and says framework protections, output encoding and HTML sanitization “will provide the best protection for your application.” It files a Content-Security-Policy under other controls, as “an additional layer of defense” that “should not be your primary defense mechanism.”
For links, my working rule is to let only https:, mailto: and relative URLs through; the javascript: scheme is the classic miss, and OWASP’s own summary allow-lists http and https URLs for an untrusted href or src.
Input validation helps, and it still leaves the bug in place. The same string is harmless inside a paragraph and dangerous inside an href, so the protection has to sit where the text is output; input validation for a web app covers the request side. A web application firewall sits in front of the app and filters requests, and the unsafe line of code is still there behind it. Neither will prevent XSS attacks on its own, and a firewall cannot stop XSS attacks that never leave the browser, as the nets section below explains.
What cross-site scripting (XSS) attacks are, and what they can do
Cross-site scripting, or XSS, is a page including untrusted text without neutralizing it, so a visitor’s browser runs an attacker’s script as if your site served it. MITRE lists it as CWE-79. The script can do what your own front-end code can do for the signed-in user, including calling your API.
XSS stands for cross-site scripting, and it has nothing to do with CSS, the stylesheet language. In cyber security catalogs, XSS is CWE-79, “Improper Neutralization of Input During Web Page Generation (‘Cross-site Scripting’)”, which MITRE describes as a product that “does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.” If a researcher emails you about an XSS vuln, this is the bug they mean; JavaScript injection is the same bug named by its payload.
As I read it, an XSS injection gives the attacker whatever your front-end code has for the signed-in user: it can read the page, call your API with their session, change their email address, and read any cookie that is not marked HttpOnly. MDN’s guide says the injected code “can then do anything that the site’s own code can do”, including making “HTTP requests with the user’s credentials” and reaching “any content in local storage”. When XSS is used to steal a cookie, the script reads it through document.cookie; the defensive answer is to set HttpOnly on the session cookie, which MDN says “forbids JavaScript from accessing the cookie”. If the app keeps its session token in localStorage instead, there is no flag to set and any cross-site scripting injection can read it; that storage choice is a JWT security question. On an admin screen, the script acts as the admin.
Every cross-site scripting (XSS) vulnerability is also an injection bug in the OWASP sense. In the OWASP Top 10, 2025 edition, cross-site scripting sits inside A05 Injection, and that category’s page lists CWE-79 among its mapped weaknesses. Reviewing the app category by category is how to test OWASP Top 10 vulnerabilities.
Why it matters in an AI-built app: where user text becomes code
Across my third-party audit corpus, the Input, Injection & Abuse pillar averages 61.9 out of 100, scored on 21 of the 21 third-party apps. Those 21 are apps I audited in June and July 2026, a selected set of audited apps rather than a random sample or a rate for AI-built apps in general. How that score compares with benchmark studies of raw model output is covered in security statistics for vibe-coded apps.
My reading of why the risk stays: modern frameworks escape text by default, so the bug lives where that default is switched off, and generated code switches it off for ordinary reasons, such as rendering markdown, showing rich text or showing the model’s formatted answer. The feature names in the table come from each project’s docs; the search and the safe form in each row are my working rules.
| Sink | Where generated code uses it | The search that finds it | The safe form |
|---|---|---|---|
dangerouslySetInnerHTML (React, Next.js) | Rendering markdown, rich-text editor output, CMS content or a model’s reply | dangerouslySetInnerHTML | Render as text, or pass the HTML through an allow-list sanitizer first |
v-html (Vue), {@html} (Svelte) | The same features in Vue and Svelte apps | v-html, @html | Same as above |
innerHTML, outerHTML, insertAdjacentHTML, document.write | Hand-written DOM code: widgets, toasts, embeds | Those four names | textContent for text; a sanitizer for HTML |
An href or src built from user input | Profile links, “website” fields, redirect targets | href= and src= fed by a variable | Allow https:, mailto: and relative URLs only |
| Unescaped server template tags | Server-rendered pages and emails | EJS <%-, Handlebars {{{, Django |safe, Rails raw and html_safe, Thymeleaf th:utext | The escaped tag (<%=, {{ }}, th:text) |
| HTML emails and PDFs built by joining strings | Receipts, invites, exported reports | Template literals that mix markup and a variable | An escaping template engine |
| A server error page that echoes a query parameter | 404, search and “not found” pages | Request parameters written into a response body | Encode the value, or leave it out |
| An uploaded SVG or HTML file served from your own origin | Avatars, attachments, logos | The upload handler and the headers it serves files with | Serve as an attachment or from a separate origin |
OWASP’s DOM-based XSS prevention cheat sheet lists innerHTML, outerHTML, document.write and document.writeln as dangerous HTML methods, and says the best way to fix DOM-based XSS is to use the right output method, such as textContent. MDN adds insertAdjacentHTML() to the list of APIs that interpret a string as HTML. The upload controls behind the last row are covered in file upload testing.
The newest route runs through the model. In the same audits, 8 of the 14 AI apps had a live prompt-injection path, with untrusted text flowing straight into the model’s instructions. Like the pillar score, that count describes the apps I chose to audit, not AI apps as a whole. A model reply rendered as HTML can turn that path into script in the user’s browser, so model output is untrusted text like any other; what prompt injection is covers the model side. Admin dashboards are where stored content usually fires, in my reading, because they render every user’s input with full privileges.
Picture a founder who asks the coding assistant to show customer support messages with formatting on the admin screen. The generated React component converts each message from markdown to HTML with a library whose docs say it does not sanitize its output, then hands the result to dangerouslySetInnerHTML, which displays whatever HTML it is passed. A message that contains markup is then rendered as markup in the admin’s signed-in session instead of shown as text: a stored route that fires on the screen with the most privileges. The fix is to sanitize the converted HTML with an allow-list, or turn raw HTML off in the renderer, and then run check 2 below on the admin screen. The lesson I take from it: the escaping was switched off in one line, so that line, not the framework, is where the search starts.
Cross-site scripting (XSS) and SQL injection are often asked about together because both are untrusted text treated as code: one runs in the visitor’s browser, the other in your database. The database half is SQL injection prevention, and the difference has its own answer in the questions at the end. For the broader pass, the 12-check vibe coding security list leaves cross-site scripting outside its twelve checks, as its own “What this list deliberately leaves out” section says.
How it works: the types, the example, sanitizing, your framework, and CSRF
Each part below is the same mechanism, untrusted text reaching a place that runs it, looked at from a different side.
Stored, reflected and DOM XSS
XSS has 3 types, named by where the script comes from. Stored: saved by the server and served to other users later. Reflected: echoed from the request, usually a link. DOM-based: front-end code writes attacker-controlled data into a sink, so the bug sits in your JavaScript. Output encoding and safe sinks fix all three.
| Type | Where the script comes from | Who is hit | Where the bug is | What fixes it |
|---|---|---|---|---|
| Stored XSS | Text the server saved earlier: a comment, a profile name, a support ticket | Every user who views that content later, admins included | Server templates or API rendering | Encoding on output; a sanitizer for rich text |
| Reflected XSS | The current request, usually a URL parameter | The person who follows a crafted link | Server templates, search and error pages | Encoding on output |
| DOM-based XSS | A value front-end code reads: location, document.referrer, postMessage data, stored client state | The person who loads the crafted page | Your own JavaScript | Safe sinks such as textContent |
Stored XSS is the type of attack the server remembers. MDN’s guide to cross-site scripting calls the comment case “stored or persistent XSS” and “particularly severe, because the infected content will be served to all users who access the page, every time they access it.” Comments, display names, support tickets and anything an admin reviews are where a stored cross-site scripting attack usually sits.
A reflected XSS attack needs the victim to follow a crafted link: the text arrives in the request, usually as a URL parameter, and the response echoes it back. A search page that prints the query back in its “no results” message is the textbook reflected cross-site scripting (XSS) example, and MDN’s guide builds its server-side example on exactly that kind of search page. Error pages that repeat a bad parameter are the other usual place. Cross-site scripting in a URL is the reflected or DOM type, not a fourth kind.
A DOM-based XSS attack never needs the server to echo anything. Front-end code reads a source such as location or a postMessage payload and writes it into a sink such as innerHTML. OWASP’s DOM Based XSS page notes that the part of a URL after the ”#” “is not sent to the server by the browser”, so an attack carried in the fragment means “the payload is never sent to the server.”
OWASP’s types of cross-site scripting adds that the three attack types “overlap”, and sorts them into server XSS and client XSS, with DOM-based XSS “a subset of Client XSS”. Blind XSS is a variant of the stored type: PortSwigger’s documentation describes it as “a type of stored XSS in which the data exit point is not accessible to the attacker”, such as an admin screen the sender cannot open. The column that matters to an owner is where the bug is: server templates for the first two types, your own JavaScript for the third. My reading is that a scanner which only reads server responses can miss a DOM XSS attack for that reason, and that single-page apps shift most of the risk to the DOM type.
A script XSS example, read defensively
The standard XSS example is a script tag that calls alert(1). It is a harmless proof that a string ran as code in the page’s origin. On a safe page the same input appears as literal characters, and the page source shows its angle brackets escaped as < and >.
In the sources linked on this page, the usual cross-site scripting (XSS) attack example is exactly this: OWASP’s XSS prevention cheat sheet uses a script tag that calls alert as its example attack for an HTML context, and the Rails security guide calls one “the most straightforward test to check for XSS” and notes that “most XSS examples simply display an alert box.” The script proves one thing, that the text was executed as code in your page’s origin, which is why owners use it on their own apps and why it is the only XSS sample this page prints. Here it is going through an EJS server template, first with the raw tag and then with the escaped tag:
<%# comment = "<script>alert(1)</script>" %>
<p><%- comment %></p> <%# raw tag: the browser runs the script %>
<p><%= comment %></p> <%# escaped tag: the reader sees text %>
<%# what the escaped tag sends to the browser: %>
<p><script>alert(1)</script></p>
EJS documents <%= as output that is “HTML escaped” and <%- as “the unescaped value”. In the browser the same cross-site scripting alert behaves differently: MDN’s innerHTML reference says the property does prevent script elements from executing when they are injected, and in the same passage warns that it is open to many other ways of crafting HTML that runs JavaScript. That is why check 2 below pairs the proof string with a plain bold tag: the bold text shows up even where a script tag stays silent. This page stops there, with no evasion variants, no encodings and no handler lists, because every XSS example code snippet beyond the harmless one helps an attacker more than an owner.
HTML injection, CSS injection and images: sanitizing what you must allow
HTML you must render, such as rich text or markdown, goes through an allow-list sanitizer after every transformation. User text never goes into CSS, where it can restyle the page and leak data. An uploaded SVG can carry script, so my working rule is to serve it as an attachment or from a separate origin.
HTML injection is markup without script. A classic HTML injection example is a fake sign-in form or a misleading link placed into your page; the Rails security guide describes an injected login form that “looks the same as the site’s original, but transmits the username and password to the attacker’s site.” The same output encoding stops it.
| What you accept | The risk | Safe handling |
|---|---|---|
| Rich text from an editor | Markup and event handlers rendered as live HTML | An allow-list sanitizer on the way out, and again after any transformation |
| Markdown | Raw HTML passed straight through to the page | Turn raw HTML off in the renderer, or sanitize the rendered output |
| Colors, fonts or themes | CSS injection that restyles the page or leaks values | A fixed set of theme values; never user text inside CSS |
| Image URLs | A javascript: or other unexpected scheme in src | The same URL allow-list as links |
| Uploaded SVG or HTML files | A document that runs script in your origin | Attachment download or a separate origin, or rasterize; X-Content-Type-Options: nosniff |
My working rule for rich content is to sanitize on the way out and again after any transformation, because OWASP’s cheat sheet warns that “if you sanitize content and then modify it afterwards, you can easily void your security efforts.” DOMPurify describes itself as “a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG”, and OWASP’s cheat sheet recommends it for HTML sanitization. The browser’s own answers are arriving: on MDN as of September 27, 2026, the HTML Sanitizer API is marked “Limited availability” and not Baseline, while Trusted Types is “Baseline 2026”, working across the latest browsers since February 2026.
Markdown renderers differ, so check yours. markdown-it calls itself “Safe by default”, and its html option, which enables HTML tags in the source, defaults to false outside the CommonMark preset. marked says plainly that it “does not sanitize the output HTML.” The rule either way: turn raw HTML off, or sanitize what the renderer produces.
CSS injection needs no script tag at all. OWASP’s guide to testing for CSS injection says injected CSS “may lead to cross-site scripting or data exfiltration”, including extracting values “using CSS selectors and functions able to generate HTTP requests”. That is the CSS XSS risk in one line: never interpolate user text into a style attribute or stylesheet, and offer a fixed set of theme values instead.
Images need two things. The plain img XSS route is an img tag whose src comes from user input, and it goes through the same URL allow-list as links. SVG is a document that can carry its own script element, so an image XSS through an uploaded SVG is real. My working rules: serve uploaded SVGs with Content-Disposition: attachment or from a separate origin, or rasterize them, and send X-Content-Type-Options: nosniff; the full header set is covered in the nets section below.
XSS filtering by stripping tags with a regular expression is the defense that fails; the Rails security guide makes the same point about blocklists, “Restricted lists are never complete.” The old browser filters are gone too: MDN marks X-XSS-Protection as deprecated and recommends Content-Security-Policy “instead of XSS filtering.”
JavaScript and Java XSS: what the framework escapes for you
React, Vue, Angular, Svelte, Django, Rails and Thymeleaf escape text by default, and each documents a way to switch that off, from dangerouslySetInnerHTML to th:utext. JavaScript and Java XSS in a framework app starts at that switch, which makes a code search the fastest first check.
| Framework or engine | Escapes text by default? | The escape hatch to search for | Note |
|---|---|---|---|
| React, Next.js | Yes: values in JSX are encoded | dangerouslySetInnerHTML | React 19 replaces javascript: URLs with functions that throw errors; 16.9 only warned |
| Vue | Yes: content is automatically escaped | v-html | Vue’s guide flags javascript: URLs in bindings |
| Angular | Yes: untrusted values are sanitized and escaped | bypassSecurityTrustHtml and the other bypassSecurityTrust methods | Sanitizes HTML and URLs |
| Svelte | Yes: expressions are stringified and escaped | {@html} | Never render unsanitized content |
| EJS | <%= escapes | <%- | |
| Handlebars | {{ }} escapes | {{{ }}} and SafeString | |
| Django | Yes, on by default | |safe, {% autoescape off %}, mark_safe | |
| Jinja | Not enabled by default | Autoescape left off, |safe | select_autoescape is the recommended setup |
| Rails | Yes: escaping tags is the default | raw, html_safe | No version stated in the guide |
| JSP with JSTL | c:out escapes (escapeXml defaults to true) | escapeXml="false"; bare expressions: not stated in the Jakarta tag docs | |
| Thymeleaf | th:text escapes | th:utext |
The React row’s warning is in React’s dangerouslySetInnerHTML reference: “If the HTML inside isn’t trusted (for example, if it’s based on user data), you risk introducing an XSS vulnerability.” OWASP’s cheat sheet adds that React “cannot handle javascript: or data: URLs without specialized validation.” React 19’s changelog covers javascript: URLs only, so data: URLs still need the scheme check. Vue’s security guide says user-provided HTML “can never be considered 100% safe” outside a sandboxed iframe or a place only its author sees, and Angular’s security guide lists the five bypassSecurityTrust methods that mark a value as trusted. The Rails security guide recommends a permitted list over a restricted one when you sanitize.
For Java XSS, templates cover the page body and a library covers the rest. The OWASP Java Encoder is a drop-in encoder “intended for quick contextual encoding”, with JSP tag libraries and EL functions, and its own page warns that XSS prevention “requires other defensive strategies besides encoding.” Searches for JVM XSS also hit -Xss, a JVM flag that sets the thread stack size, which has nothing to do with this bug.
Cross-site scripting in JavaScript is the usual case whatever language the server uses, for the reason given in the language question at the end. Preventing XSS attacks in JavaScript comes down to the table plus the DOM sink row earlier. The rule that falls out, my working rule: search the codebase for every entry in the hatch column, and give every hit a written reason and a sanitizer in front of it.
CSRF vs XSS: different bugs
CSRF and XSS are different bugs. XSS runs an attacker’s script inside your site and can read responses. CSRF makes the victim’s browser send a request from another site and typically cannot read the reply. XSS can defeat CSRF defenses, so CSRF protection assumes XSS is handled.
The difference between cross-site request forgery and cross-site scripting comes down to three questions:
| Question | XSS | CSRF |
|---|---|---|
| Where the attacker’s code runs | Inside your page, in your origin, in the victim’s session | On another site; only the request reaches yours, carrying the victim’s cookie |
| What it can read | Anything your own front-end code can: page content, API responses, tokens | Cross-origin reads are typically disallowed, so usually nothing |
| What stops it | Output encoding and safe sinks | CSRF tokens, Fetch Metadata or origin checks, SameSite cookies |
The dependency runs one way. A script running in your origin can read a CSRF token from the page and send same-site requests with it, which is why OWASP’s CSRF prevention cheat sheet says “Cross-Site Scripting (XSS) can defeat all CSRF mitigation techniques!” The practical difference between XSS and CSRF for an owner is the order of work: fix XSS first, then add the request checks in CSRF mitigation.
Content-Security-Policy, HttpOnly cookies and a WAF: the nets under the fix
A Content-Security-Policy without unsafe-inline stops injected inline script from running, and HttpOnly keeps the session cookie out of script’s reach. Both are nets under the fix. Neither removes the bug, and a WAF cannot see a DOM-based payload that never leaves the browser.
MDN recommends a strict CSP that uses a nonce or a hash, so an injected script element without the right one does not run, and inline event handlers and javascript: URLs are disallowed as well. OWASP calls CSP at its best “a defense-in-depth technique”, which is the right place for it: it catches the encoding bug you missed and leaves that bug in the code. Rolling one out without breaking the app, report-only first, is covered in Content-Security-Policy without unsafe-inline.
HttpOnly on the session cookie keeps it away from document.cookie, but MDN notes the cookie “will still be sent with JavaScript-initiated requests”, so the injected script can still act as the user. OWASP’s cheat sheet says WAFs “miss a class of XSS vulnerabilities that operate exclusively client-side”, and a payload in the URL fragment never reaches the server a WAF guards. My reading is that a WAF still catches noisy reflected probes; setting one up is its own task: how to set up a web application firewall. Other ways untrusted input turns into behavior have their own pages, from remote file inclusion and path traversal to SSRF and open redirects in race conditions and the other web vulnerability classes.
How to check your own app
XSS mitigation is verified with 6 checks: a code search for escape hatches and DOM sinks, a harmless proof string entered in every stored field and viewed everywhere it renders, a source-to-sink read of front-end code, a header check, a regression test per fixed screen, and an open-source scanner run on staging.
The order is my working order, strongest first, with the scanner last as a supplement to checks 1 to 5. Every cross-site scripting test here runs on an app you own, ideally a staging copy.
- 01 Search the codebase for every escape hatch in the framework table and every DOM sink (innerHTML, outerHTML, insertAdjacentHTML, document.write). Evidence: the list of hits, each with its reason and the sanitizer in front of it.
- 02 On your staging app, enter the harmless proof string and a plain bold tag into every field that is later shown to anyone: names, comments, titles, file names, support messages. View every place each one renders, including admin screens, emails and exports. Pass: the literal characters on screen. Fail: bold text or an alert. Evidence: a dated screenshot per screen.
- 03 For DOM XSS, read the front-end code for values taken from location, document.referrer, postMessage data and localStorage that flow into a sink. Evidence: each source-to-sink pair and its fix.
- 04 Read the response headers of the real app. A CSP whose script-src holds unsafe-inline does not stop injected inline script. If the session lives in a cookie, the cookie carries HttpOnly; if it lives in localStorage, record that instead. Evidence: the headers as sent, saved with the date.
- 05 Write a regression test per fixed screen that stores the proof string and asserts the rendered HTML contains the escaped form and no new element. Evidence: the test in the suite, failing on the old code and passing on the fix.
- 06 Run an open-source proxy scanner such as ZAP against staging. Evidence: the report, kept beside checks 1 to 5, never in place of them.
The only XSS testing code this page gives is the one in check 2: the harmless proof string and a bold tag. For check 6, ZAP describes itself as “Free and open source”, and its active scan rules include alerts for reflected, persistent and DOM-based cross site scripting. A free site that runs a cross-site scripting test online, whether it calls itself an XSS vulnerability scanner or a checker, should only ever check a website you own: to scan it, you hand the URL to a third party, and the results sit with them too. What each kind of scanner can and cannot prove is covered in website security check.
Keep an XSS report for every finding, whether you found it or an outside XSS tester did, in your own tracker or for a disclosure inbox: the screen, the field, the string, where it rendered, a screenshot, the fix commit and the retest date. A check that finds nothing still gets a dated line, so the next XSS vulnerability scan has something to compare against.
In the Production Hardening Sprint, deliverable 3.1 is verified this way: Submit invalid and hostile payloads and confirm safe rejection or handling. Deliverable 3.4 is verified this way: Inspect response headers and exercise the application to confirm intended protections without broken flows.
Where the sprint fits
The Production Hardening Sprint’s deliverable 3.1 validates every data-writing endpoint with explicit schemas and safe input/output handling, including injection defenses, and deliverable 3.4 configures and tests CSP, HSTS, framing restrictions and other appropriate browser security headers. Deliverable 3.7 reviews the application against the OWASP Top 10 and records findings, fixes and evidence by category, and deliverable 3.10 tests the five highest-risk externally reachable attack surfaces, remediates findings and delivers the methods and evidence. The results go into the production readiness report, deliverable 13.1, which accounts for all 123 IDs, keeps failures visible until resolved and explains genuine non-applicable items. The targeted security tests cover the five priority attack surfaces documented in the report, and formal third-party certifications and independent audit opinions are separate from the sprint deliverables. Every item is listed in the published scope.
Common questions about XSS
Are XSS attacks still common?
Yes. CWE-79, cross-site scripting, is ranked first in MITRE’s 2025 CWE Top 25 Most Dangerous Software Weaknesses, the same place it held the year before. My reading of why it persists in framework apps: the default escaping works, and the bug comes back through the documented escape hatches listed above.
Which language is commonly used by attackers for XSS attacks?
JavaScript, because it is the language every browser runs. The server can be written in Java, Python, Ruby or anything else; the injected payload still has to be something the victim’s browser will execute, which in practice means JavaScript in an HTML page.
How to detect XSS attacks?
My working order is CSP violation reports first, then request logs that show markup in query parameters or form fields, then a scanner run such as ZAP’s active scan against staging. Violation reports come from real browsers hitting blocked script, so they surface attempts a scanner never tries. Alerting on those signals belongs with security logging and monitoring.
What is the difference between XSS and SQL injection?
Both are untrusted text treated as code. XSS runs in another user’s browser and is fixed by output encoding for the context; SQL injection runs in your database and is fixed by bound parameters. The SQL side is covered in the SQL injection prevention guide linked above.
The checks in this guide show you where the app is open. The sprint below closes those gaps, tests the result and writes the evidence down.
Built it with AI. Now it has to hold up for real customers.
The Production Hardening Sprint takes the app you already have and builds the production foundation underneath it. Authentication and access rules, payments that stay consistent, error handling, monitoring, backups, automated tests and a documented handover. Our engineers work inside your existing codebase for ten working days. All 123 deliverables are included, and you get the evidence for each one.
See the Production Hardening Sprint →
$2,500 fixed price · 10 working days · One codebase