How do you prevent XSS?
Short answer
The primary defense is contextual output encoding — encode untrusted data for the exact place it lands (HTML body, attribute, JavaScript, URL). Pair that with safe DOM APIs (textContent over innerHTML), framework auto-escaping, input validation, and a Content-Security-Policy as a defense-in-depth backstop that limits what scripts can run.
XSS happens when untrusted data is interpreted as code by the browser. The whole prevention strategy follows from one principle: keep data as data. The browser switches parsing contexts constantly — HTML, attributes, JavaScript, CSS, URLs — and each context has different characters that break out of it. So the fix is not one magic function; it is doing the right encoding for the right place.
Contextual output encoding (the main control)
Encode untrusted values at the point of output, for the specific context:
- HTML body → HTML-entity encode (
<becomes<). - HTML attribute → attribute-encode and always quote the attribute.
- Inside a
<script>/ JS string → JavaScript-encode (Unicode escapes). - URL parameter → URL-encode.
Modern frameworks (React, Angular, Vue) auto-escape by default, which is why XSS often appears only where developers reach for escape hatches like dangerouslySetInnerHTML or v-html.
Safe DOM APIs
For client-side rendering, prefer textContent, setAttribute, and createElement over innerHTML, document.write, and eval. When you genuinely must render rich HTML, run it through a vetted sanitizer like DOMPurify rather than rolling your own.
Input validation — helpful, not sufficient
Validate and reject obviously bad input (allowlists, length, type) at the boundary. But validation alone cannot stop XSS, because legitimate data (a name with < in it) still needs encoding when output.
Content-Security-Policy as a backstop
A strict, nonce- or hash-based CSP that disallows inline script and eval means that even if a payload slips through, the browser refuses to execute it. It is defense in depth, not a primary control.
Interviewers want to hear "contextual output encoding" first, an understanding that validation is not enough, and CSP framed as a backstop — plus a named safe API or sanitizer.
Likely follow-ups
- Why is input validation alone insufficient to stop XSS?
- How does a strict, nonce-based CSP reduce XSS impact?
- What is the right encoding for data placed inside a JavaScript string?