XSS Prevention Checklist
Actionable XSS checklist: sinks, sanitization, CSP, cookies, URLs, markdown, and PR review prompts.
- security
- xss
- checklist
- csp
- sanitization
This is the operator’s checklist companion to the conceptual XSS guide. Use it in PR review, threat modeling, and incident retros when user-controlled data touches the DOM.
Docs: OWASP XSS Prevention, Strict CSP, Trusted Types.
1. Prefer safe sinks
- Use
textContent/ framework text bindings by default - No
innerHTML/dangerouslySetInnerHTML/document.writewith untrusted data - No
eval,new Function, stringsetTimeout
el.textContent = user.name; // OK for text
2. If HTML is required
- Sanitize with a maintained library (e.g. DOMPurify) and strict allowlist
- Sanitize at the boundary closest to render (and/or server)
- Don’t “regex out
<script>”
el.innerHTML = DOMPurify.sanitize(html, { USE_PROFILES: { html: true } });
3. URLs and navigation
- Allow only
http:/https:(or internal paths) forhref/src/location - Block
javascript:,data:where inappropriate — safe URLs - Validate redirect targets — open redirects
4. Framework-specific
- React: audit every
dangerouslySetInnerHTMLand URL attrs - Vue: audit
v-html - Angular: avoid bypassing sanitizer APIs without review
- Markdown/rich text: parser + sanitizer configured
5. Defense in depth
- CSP with nonces/hashes; avoid
unsafe-inlinelong-term — CSP - Trusted Types where supported
- Session cookies
HttpOnly; Secure; SameSite— cookies - No long-lived tokens in
localStorage— JWT pitfalls
6. postMessage & embeds
- Check
event.origin+ schema — postMessage - Sandbox untrusted iframes — sandbox
7. Server still matters
- API authz not only UI hiding
- Escape server-rendered templates
- Correct
Content-Type+X-Content-Type-Options: nosnifffor uploads
8. Test & monitor
- Payload unit tests on sanitizer wrappers
- Security headers in staging
- CSP report-only during rollout
- Bug bounty / automated scanner as assist, not sole gate
Interview out-loud
“XSS prevention is safe sinks first, sanitization when HTML is required, URL allowlists, CSP and Trusted Types, HttpOnly sessions, and careful postMessage/iframes. Checklists keep PR review honest when features demand rich HTML.”
Reviewer prompts
- What is the asset (session, PII, money movement)?
- What is the attacker capability (web, XSS, network, dependency)?
- Which control fails closed if misconfigured?
- Is the server still enforcing authz?
- Any new third party, iframe, or URL sink?
Residual risk note
Browser controls reduce likelihood and impact; they do not eliminate bugs. Prefer defense in depth: safe defaults in code, strict headers, and monitoring (CSP reports, auth anomaly alerts). When product pressure weakens a control, write down the accepted risk and a revisit date.
Related
Further depth
Teams often under-invest in this topic until an incident or CWV regression. Schedule a one-hour drill: reproduce the failure mode in DevTools, list the top three mitigations for your stack, and file tickets with owners. Revisit after the next major feature that touches networking, rendering, auth, or third parties — those are the moments regressions land. Keep primary documentation links in the runbook so on-call is not searching chat history at 2am.
Concrete artifacts to leave behind: a short architecture note, a CI assertion or header snapshot, and a dashboard panel (lab or field) that would have caught the last bug. Teaching the rest of the team the mental model matters as much as the one-line fix.
Further reading
Related guides
- Content Security Policy (CSP)Reduce XSS blast radius with CSP — script-src nonces/hashes, strict-dynamic, report-only rollout, and what CSP does not fix.
- Clickjacking and X-Frame-OptionsStop UI redress attacks with frame-ancestors CSP and X-Frame-Options; know when embedding is intentional.
- Frontend Security Threat ModelThreat-model SPAs: assets, attackers, XSS/CSRF/supply-chain, and where frontend controls actually land.
- JWT Storage PitfallsWhy localStorage JWTs are XSS bait, cookie alternatives, refresh patterns, and SPA session designs that age better.
- postMessage SecuritySecure window.postMessage: targetOrigin, event.origin checks, schema validation, and iframe bridges.