Cross-Site Scripting (XSS)

Cross-site scripting (XSS) is when an attacker gets a browser to run unintended JavaScript in the context of your site. Because modern apps render so much user-generated content, XSS is one of the most common web vulnerabilities — and a successful one can steal sessions, rewrite the page, or take over accounts.

The defense is conceptually simple: render untrusted data as text, not as HTML. Most XSS comes from a single place where that boundary was crossed.

TL;DR

Quick Example

The vulnerability and its fix in one place — let the framework escape, or escape yourself:

Types of XSS

Root Causes

XSS almost always comes from rendering untrusted strings as HTML, or feeding them to a dangerous sink:

Prevention Strategies (in priority order)

1. Output encoding — the real fix

Render untrusted data as text, in the right context (HTML, attribute, URL, JS). Modern frameworks do this by default:

2. Avoid dangerous HTML rendering

If your framework offers a raw-HTML escape hatch, treat it as privileged: only for trusted authors, only on sanitized content, ideally isolated.

3. Sanitize when you must accept HTML

If users can submit HTML, run it through a vetted sanitizer (e.g. DOMPurify). Sanitization is genuinely hard — it must strip scriptable URLs (javascript:), event handlers (on*), and SVG/MathML edge cases — so don't roll your own.

4. Content Security Policy (CSP)

CSP limits the impact even if a bug exists. A reasonable baseline:

Avoid 'unsafe-inline' for scripts; use nonces or hashes instead, and add report-to to observe violations. See Security Headers.

Safe Patterns by Stack

Common Mistakes

Assigning untrusted input to innerHTML

Shipping a CSP that allows inline scripts

FAQ

Does input validation prevent XSS?

It helps, but it isn't sufficient. The reliable fix is context-aware output encoding when you render data. Validation reduces the attack surface; encoding closes the hole.

Is React immune to XSS?

No. React escapes values by default, which prevents most XSS — but dangerouslySetInnerHTML, javascript: URLs in href, and injecting into <script>/<style> can still introduce it.

What's the difference between stored and reflected XSS?

Reflected XSS executes from a single crafted request (the payload is in the URL or form). Stored XSS is persisted server-side and runs for every user who views it, which makes it far more dangerous.

Where does CSP fit in?

CSP is a backstop, not a primary fix. It limits what a successful injection can do (e.g. block inline scripts and exfiltration), buying safety margin while you fix the root cause.

Related Topics

References