Intro
Cross-Site Scripting (XSS) is when attacker-controlled data is parsed as code by the browser. Three classes: reflected, stored, DOM-based. Defensively framed.
XSS — what it is
EXAMPLE
// SCOPE: defensive learning on the bundled lab app. Authorised testing only.
// Do not test against systems you do not own or have written permission to test.
// ===== The mechanism =====
// User input ends up in a context (HTML, JS, attribute, URL) where the browser
// PARSES it. Instead of being treated as data, it becomes code.
// ===== The three classes =====
// 1. Reflected: payload in the request is reflected into the response (search pages)
// 2. Stored: payload persisted (DB / file) and served later to others (comments)
// 3. DOM-based: client JS reads untrusted input (location, postMessage) and writes to DOM
// ===== Default-escape (the most important defence) =====
// Modern templates auto-escape by default:
// Blade {{ value }} escapes HTML
// React {value} escapes HTML in text children
// Vue {{ value }} escapes HTML
// Handlebars {{value}} escapes; {{{value}}} does NOT
// Every framework has an OPT-OUT (raw HTML); review every use.
// ===== A safe pattern =====
// User-supplied comment rendered in HTML:
// server: htmlspecialchars($value, ENT_QUOTES | ENT_HTML5)
// client: textContent = value // never innerHTML
// Need rich text? Sanitise with an allowlist (DOMPurify, sanitize-html).
// ===== Content Security Policy =====
// The safety net even when escaping fails.
// Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-<rand>';
// Inline scripts must carry the nonce; everything else is rejected.
// ===== Cookies =====
// HttpOnly + Secure + SameSite=Lax (or Strict) — even if XSS happens,
// document.cookie cannot read session cookies.
// ===== Detection checklist =====
// Code review for:
// - innerHTML / outerHTML / document.write
// - {!! ... !!} (Blade) / v-html / dangerouslySetInnerHTML
// - Building HTML by string concatenation
// - User input flowing into href / src without scheme validation
// ===== Recovery if you find one =====
// 1. Sanitise + escape at every render path
// 2. Rotate sessions if cookies could have been exposed
// 3. Audit similar paths in the codebase
// 4. Add a test that locks in the fix
// ===== Patterns to internalise =====
// - Treat input as data until you opt into HTML deliberately
// - Default-escape; sanitise allowlist when you need rich text
// - Strict CSP with nonces, never unsafe-inline
// - HttpOnly + Secure + SameSite cookies always
// ===== Pitfalls =====
// - Rolling a regex-based HTML sanitiser
// - Allowing javascript: URLs in href
// - Re-rendering stored HTML raw because 'we already sanitised on input'
// - Treating XSS as only a logged-in problem
Why it matters
XSS is a templating problem with three faces. Default-escape, sanitise via allowlist when you genuinely need HTML, ship strict CSP, and harden cookies. The three classes all reduce to the same rule: data must never be parsed as code.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
// Cross-Site Scripting (XSS): the attacker's script runs in the victim's browser // in YOUR origin — so it sees the victim's cookies, DOM, and session. // Caused by mixing untrusted data into HTML / JS without proper encoding.Try it Yourself »
Exercise
Safe property for assigning untrusted strings as text.
el.
= userInput;
camelCase, ends in Content.
Discussion
Loading…