XSS prevention through proper output escaping
Why it matters
XSS (CWE-79, OWASP A03 Injection) lets attackers inject JavaScript into pages viewed by other users — stealing session cookies, capturing keystrokes, redirecting to phishing pages, or silently performing actions as the victim. Stored XSS, where the payload is saved in a database and rendered to every visitor, can compromise thousands of accounts from a single submission. NIST 800-53 SI-10 requires input sanitization. React's JSX auto-escaping prevents most XSS, but dangerouslySetInnerHTML with unsanitized database content bypasses the protection entirely. A comment field or profile bio rendered unsanitized is all an attacker needs.
Severity rationale
High because stored XSS turns every page view into a potential account takeover — a single injected payload runs in every victim's browser session without further attacker interaction.
Remediation
Sanitize user-generated HTML with DOMPurify before passing it to dangerouslySetInnerHTML. Better: avoid dangerouslySetInnerHTML entirely by using react-markdown for user content.
When you must render raw HTML:
import sanitizeHtml from 'sanitize-html'
const clean = sanitizeHtml(userHtml, {
allowedTags: ['b', 'i', 'em', 'strong', 'a', 'p', 'br', 'ul', 'li'],
allowedAttributes: { a: ['href', 'rel'] },
allowedSchemes: ['http', 'https', 'mailto'],
})
// Then render:
<div dangerouslySetInnerHTML={{ __html: clean }} />
Search the codebase for dangerouslySetInnerHTML, innerHTML =, and v-html and audit each one. Any that render database-sourced content must sanitize first.
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the Security Hardening Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- cwe · CWE-79 — Cross-site Scripting (XSS)
- owasp:2021 · A03 — Injection
- nist:rev5 · SI-10 — Information Input Validation
Taxons
History
- 2026-04-18·v1.0.0·Initial import from security-hardening·automated
- 2026-04-20·v1.1.0·Add Phase 6.0 detect-rg snippet for XSS-prone DOM-mutation API detection·by cakleinman