Testing, Pitfalls & Checklist
The finale turns the course into practice: how to test for XSS, the broken-defence patterns to recognize in review, and a copy-pasteable hardening checklist that pulls all ten chapters together.
How to Test for XSS
- Map every input → output flow — URL params, form fields, headers, stored data, and where each is reflected. Don't forget indirect reflections (a name set on one page, shown on another).
- Inject a unique benign marker — e.g.
xss7421— and find where it lands in the response/DOM. This tells you the context (Chapter 3) before you craft a payload. - Try context-appropriate payloads — a tag in HTML body, a quote-breakout in an attribute, a scheme in a URL — or one polyglot probe (Chapter 4).
- Check DOM XSS separately — trace client-side sources (
location,hash) to sinks (innerHTML,eval); these won't show in server testing (Chapter 2). - Confirm execution safely — use
console.logor a request to a collector you control, not noisyalert()(Chapter 4).
The Broken-Defence Catalogue
| Broken defence | Why it fails | Chapter |
|---|---|---|
| Blocklist filtering ("strip <script>") | infinite bypasses — case, entities, no-script vectors | 4 |
| HTML-encoding everywhere | wrong for JS/URL/unquoted-attribute contexts | 3,6 |
| Encoding at input, storing encoded | double-encoding; can't know output context | 6 |
| Hand-rolled HTML sanitizer | bypassed via parsing quirks / mXSS | 7 |
| "We validate input" | free-text legitimately has < > " ' | 7 |
CSP with 'unsafe-inline' | re-allows injected inline scripts | 8 |
Unsanitized dangerouslySetInnerHTML/v-html | bypasses framework auto-escaping | 9 |
| HttpOnly treated as an XSS fix | blocks cookie read only; script still acts | 1,5 |
The Hardening Checklist
dangerouslySetInnerHTML, v-html, bypassSecurityTrust…, raw innerHTML/evalhttp/https/mailto; reject javascript:/data:'unsafe-inline'; roll out via report-only; consider Trusted TypesHow the Course Fits Together
The arc: understand the bug (Ch. 1 — data vs code; same-origin power), the variants (Ch. 2 types, Ch. 3 contexts), the attack (Ch. 4 payloads, Ch. 5 impact), then the defences bottom-up — output encoding as the foundation (Ch. 6), sanitization for real HTML (Ch. 7), CSP as the backstop (Ch. 8), framework auto-escaping & Trusted Types (Ch. 9), and operational testing/hardening (Ch. 10). It also closes the loop with the CSRF course: XSS is the bug that defeats CSRF defences, which is why it's foundational and worth fixing first.
Hands-On Exercises
Write a step-by-step XSS test plan for a single input field, from mapping the reflection to confirming execution. Include how you'd determine the injection context first, and how you'd separately check for DOM-based XSS that a server-side scanner would miss.
📄 View solutionAudit this app against the broken-defence catalogue: it strips <script> from input, HTML-encodes all output, sets a CSP with 'unsafe-inline', and renders comments with v-html. List every flaw and the correct fix for each.
Produce a prioritized XSS hardening plan for a React app with a cookie session and a rich-text comment feature. Order the defences, justify the ordering (what's foundational vs backstop), and explain why fixing XSS also protects the app's CSRF defences.
📄 View solutionChapter 10 Quick Reference
- Test: map input→output flows · inject a unique marker to find the context · context-appropriate payloads · check DOM sources→sinks separately · confirm with a benign marker
- Scanners (Burp/ZAP/Dalfox) catch reflected/stored well but miss DOM XSS & second-order — pair with manual review of the escape hatches
- Broken defences: blocklists · HTML-encode-everywhere · encode-at-input · hand-rolled sanitizer · "we validate" ·
'unsafe-inline'CSP · unsanitizedv-html/dangerouslySetInnerHTML· HttpOnly-as-fix - Checklist: context-aware encoding · store raw/encode late · DOMPurify for HTML · audit escape hatches · URL-scheme allowlist · strict nonce CSP + Trusted Types · HttpOnly/Secure/SameSite · validate strict fields · test
- The one principle: keep untrusted input as data, never code — every defence is one expression of it
- Never weaken encoding to make a feature work — that's the recurring reopening mistake
- XSS closes the loop with CSRF: it defeats CSRF defences, so it's foundational — fix it first
★ XSS — Cross-Site Scripting Complete — 10 / 10 chapters
From "untrusted input becomes code" and the same-origin power of an injected script, through the three types, injection contexts, payload anatomy and real-world impact, then the full defence stack — output encoding, sanitization, CSP, framework auto-escaping, and Trusted Types — to testing and a deployable checklist. Paired with the CSRF course, you now have both halves of the client-side-injection picture, and the throughline that ties them: keep untrusted input as data, and fix XSS first.