iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up
Next »

Summary

A one-screen summary of XSS: what it is, where it comes from, how each context wants to be escaped, and the safety net (CSP, Trusted Types, sanitisation) that catches the bugs your output encoding misses. Keep this open during code review.

XSS in one screen

EXAMPLE
# ===== What XSS is =====
# Attacker-controlled text is rendered as code (HTML / JS / URL) inside the
# browser of a victim. The attacker steals cookies, scrapes the page, takes
# actions as the victim, or pivots into account takeover.

# ===== Three flavours =====
# Reflected:  bug in a URL parameter or query, echoed back into the response.
# Stored:     bug in user-saved content (comment, profile, message) that hits
#             every viewer who loads it later. Highest blast radius.
# DOM-based:  client-side JS reads location/cookie/postMessage and writes into
#             the DOM unsafely. Server logs nothing.

# ===== The output-encoding rule =====
# Pick the encoder by CONTEXT, not by familiarity.
#
# HTML BODY                -> htmlspecialchars / Blade {{ }} / React {value}
# HTML ATTRIBUTE (quoted)  -> htmlspecialchars + QUOTED attribute
# JS STRING LITERAL        -> json_encode (PHP) / JSON.stringify (Node)
# URL PARAMETER            -> urlencode / encodeURIComponent
# CSS VALUE                -> escape with CSS escaping; whitelist (rare today)

# Wrong encoder for the wrong context = bug. The most common bug is HTML
# encoding into a JS string literal -- still vulnerable.

# ===== Framework safe defaults =====
# Blade   {{ $x }}                  safe;  {!! $x !!} bypasses
# React   {value}                   safe;  dangerouslySetInnerHTML bypasses
# Vue     {{ value }}               safe;  v-html bypasses
# Angular {{value}}                 safe;  bypassSecurityTrust* bypasses
# Sveltekit {value}                 safe;  @html bypasses
#
# Treat every escape hatch as a code-review red flag with a written rationale.

# ===== Sanitise, do not regex =====
# If you must render user HTML (rich text comments), sanitise:
# - DOMPurify (JS)
# - HTMLPurifier (PHP)
# - bleach (Python)
# Never with a hand-rolled regex.

# ===== Defence in depth =====
# 1. CSP (Content-Security-Policy)
#    default-src 'self';
#    script-src 'self' 'nonce-r4nd0m';
#    style-src 'self';
#    object-src 'none'; base-uri 'self';
#    frame-ancestors 'self';
#    require-trusted-types-for 'script';
#
# 2. Trusted Types — REQUIRE policies before writing to innerHTML etc.
#    Pairs with CSP 'require-trusted-types-for' to make innerHTML throw on
#    raw strings. Effective in Chromium-based browsers.
#
# 3. Output-encoded everywhere AS the primary defence.
# 4. HSTS + upgrade-insecure-requests prevent attacker downgrades.
# 5. Cookie flags: Secure, HttpOnly, SameSite=Lax for session cookies.
#    HttpOnly is the second-line defence: stolen XSS cannot read the cookie.

# ===== Sinks to grep for =====
# JS:    .innerHTML, .outerHTML, .insertAdjacentHTML, document.write, eval, Function()
# React: dangerouslySetInnerHTML
# Vue:   v-html
# Angular: bypassSecurityTrustHtml
# PHP:   echo $_GET, echo $_POST, {!! $x !!}
# Templates: any 'raw' / 'safe' filter

# ===== Quick review checklist =====
# - [ ] Every user-text echo uses the framework default escaper
# - [ ] Any escape hatch ({!! !!}, v-html, dangerouslySetInnerHTML, @html) has a comment
# - [ ] CSP is set, with a nonce-based script-src and object-src 'none'
# - [ ] Cookies have HttpOnly + Secure + SameSite
# - [ ] Trusted Types on (Chromium fleets) where supported
# - [ ] User-supplied URLs are validated for protocol (https / mailto only)

# ===== Things that look like XSS defence but are NOT =====
# - WAF rules alone (bypassed by encoding tricks)
# - Removing certain tags via regex (DOMPurify exists for a reason)
# - 'We trust authenticated users' (account takeover compromises the trust)
# - Sticking a CAPTCHA in front of the input form

# ===== Scoring =====
# 8 / 8 boxes checked -> you can lead an XSS review on this codebase
# 6 / 8                -> revisit xss/cheatsheet
# < 6                  -> a focused half-day with OWASP XSS Prevention Cheat Sheet

Why it matters

A nonce-based CSP + Trusted Types is the safety net under output encoding. Even if a future PR slips a raw innerHTML in, Trusted Types throws at runtime and CSP refuses to execute the injected script. Combine that with HttpOnly cookies and a successful XSS becomes a logged event that cannot steal the session — not the catastrophe it would be without those layers.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// Next: deep-dive Trusted Types policies, modern CSP nonces, Sanitizer API.
Try it Yourself »

Discussion

Loading…

Next »