Cross-site scripting was first documented in 2000. Twenty-six years later, it remains one of the most common web vulnerabilities we find. In fact, XSS appears in over 60% of our web application audits — and not just the trivial reflected variety.
If you thought XSS was a solved problem, it isn't. Here's why.
XSS by the Numbers
60%+
Audits with XSS
#3
OWASP Injection Rank
$7.2K
Avg Bug Bounty Payout
26 yrs
And Counting
As we covered in our OWASP Top 10 breakdown, injection vulnerabilities remain a top concern — and XSS is the most prevalent injection type in web applications.
The Three Flavors
XSS Variants
Reflected XSS
User input is immediately reflected in the response without sanitization. The attacker crafts a malicious URL and tricks the victim into clicking it. Payload executes once.
Stored XSS
Malicious input is saved to the database and rendered to every user who views the affected page. Comments, profiles, forum posts, and chat messages are classic vectors. Payload executes for every viewer.
DOM-based XSS
The vulnerability exists entirely in client-side JavaScript. The page's own scripts read from a controllable source (URL fragment, postMessage, localStorage) and write to a dangerous sink (innerHTML, document.write, eval).
Why It Persists
1. The Attack Surface Keeps Growing
Modern web applications have exponentially more JavaScript than a decade ago. SPAs, client-side routing, and rich interactive UIs create thousands of potential injection points:
- React's
dangerouslySetInnerHTML(the name is a warning most teams ignore) - Angular's
bypassSecurityTrustHtmland template injection - Vue's
v-htmldirective - Server-side rendering (SSR) hydration mismatches
- Third-party widget embeds and analytics scripts
- Markdown renderers that allow HTML passthrough
2. CSP Adoption Is Still Low
Content Security Policy is the most effective defense against XSS — it tells the browser which scripts are allowed to execute. Yet as we detailed in our security headers guide, over 73% of applications are missing CSP entirely.
⚠️CSP Is Hard to Get Right
Even when CSP is deployed, it's often misconfigured. Common mistakes: using unsafe-inline (which defeats the purpose), overly broad domain allowlists, or missing directives for object-src, base-uri, and form-action.
3. New Contexts, Same Mistakes
XSS isn't just about <script> tags anymore. Modern attacks target:
SVG uploads
SVG files can contain JavaScript via onload handlers and script elements. Upload an SVG "image" that executes code when rendered.
PDF generation
Server-side PDF generators that process HTML (wkhtmltopdf, Puppeteer) can be exploited for SSRF and data exfiltration via XSS payloads in the generated content.
Markdown rendering
Markdown-to-HTML converters that allow raw HTML or JavaScript URLs in links enable stored XSS in documentation, comments, and wikis.
Email templates
HTML email templates rendered with user data create XSS in email clients — and can lead to phishing or credential theft.
The Modern XSS Kill Chain
What can an attacker actually do with XSS? Much more than pop an alert box:
Session hijacking
Steal session cookies (if HttpOnly isn't set) or tokens from localStorage. Impersonate the victim completely.
Credential theft
Inject a fake login form over the real page. The user "re-authenticates" and sends credentials to the attacker.
Keylogging
Install a JavaScript keylogger that captures everything the user types on the page — passwords, credit cards, messages.
Cryptocurrency theft
For Web3 applications: trigger wallet signing requests that transfer tokens to the attacker's address. The user sees a legitimate-looking transaction prompt.
Worm propagation
Stored XSS that modifies the victim's own content to include the payload — spreading to everyone who views their profile, creating a self-propagating worm.
🛑XSS in Web3 = Direct Financial Loss
For applications with wallet integrations, XSS is critical severity. An attacker can use XSS to trigger wallet transactions, approve token spending, or redirect bridge transfers. This isn't theoretical — it's happened to multiple DeFi frontends.
Defense in Depth
Insufficient Defenses
- •Blocklist-based input filtering (easily bypassed)
- •Client-side validation only
- •WAF rules as the only protection
- •Manual escaping in templates
Effective Defenses
- •Context-aware output encoding (HTML, JS, URL, CSS contexts)
- •Strict Content Security Policy with nonces
- •Framework auto-escaping enabled and never bypassed
- •HttpOnly + Secure + SameSite flags on all cookies
The Defense Stack
Encode
Context-aware output encoding at the template layer — HTML, JS, URL, CSS each need different encoding
CSP
Deploy strict Content Security Policy with nonce-based script allowlisting — no unsafe-inline
Cookies
Set HttpOnly, Secure, and SameSite=Strict on all session cookies
Test
Automated XSS scanning on every deployment plus manual testing for DOM-based and context-specific XSS
How We Find XSS
Our Web Security Auditor uses a multi-layered approach:
- AI-powered crawling discovers every input point — form fields, URL parameters, headers, JSON bodies, file uploads
- Context-aware payload generation tests each input with payloads specific to the rendering context (HTML body, attribute, JavaScript string, URL)
- DOM analysis traces data flow from sources (URL, postMessage, storage) to sinks (innerHTML, eval, document.write) in client-side JavaScript
- Human expert review for complex DOM-based XSS, mutation XSS, and framework-specific bypasses
As we discussed in Why AI-Assisted Security Auditing Finds More Vulnerabilities, the combination of AI breadth and human depth is what catches the XSS that scanners miss.
Worried about XSS in your application? Our Web Security Auditor tests every input and rendering context automatically, and our expert review catches the complex DOM-based and framework-specific XSS that automated tools miss.