Cross-Site Scripting (XSS) remains one of the most pervasive vulnerabilities in web applications, consistently appearing in the OWASP Top 10 and accounting for a significant proportion of findings in every web application penetration test. Despite decades of awareness, XSS persists because modern web applications are more dynamic than ever — and dynamic content without proper output encoding is inherently dangerous.
Understanding the Three Types of XSS
XSS attacks fall into three distinct categories, each with different exploitation and remediation characteristics.
Reflected XSS
Reflected XSS occurs when unsanitized user input is immediately reflected back in the HTTP response. The classic example is a search parameter: https://example.com/search?q=<script>alert(1)</script>. The payload travels in the URL, which must be delivered to the victim — typically via phishing email or malicious link. Because the payload is not stored, reflected XSS requires active delivery but is extremely common.
Stored XSS
Stored (persistent) XSS occurs when attacker-supplied input is stored in a database and later rendered to other users. A malicious script in a comment field, forum post, or user profile that executes in every visitor's browser is stored XSS. This variant is far more severe because it requires no active delivery — victims are compromised simply by visiting the page.
DOM-Based XSS
DOM-based XSS occurs entirely client-side when JavaScript reads attacker-controlled data (from the URL fragment, document.referrer, or postMessage) and writes it to a dangerous sink (innerHTML, document.write, eval()). The payload never reaches the server, making it invisible to server-side WAFs and difficult to detect in access logs.
XSS Testing Methodology
A systematic XSS assessment covers every input vector: URL parameters, HTTP headers (User-Agent, Referer, X-Forwarded-For), form fields, JSON/XML request bodies, file upload names, and WebSocket messages. For each input, testers probe:
- Context identification: Is the input reflected in HTML content, HTML attribute, JavaScript string, URL, or CSS context? Each requires different payloads.
- Filter evasion: Are there blacklists that can be bypassed via case variation (<ScRiPt>), encoding (%3cscript%3e), or alternative event handlers (onmouseover, onerror, onload)?
- CSP evaluation: Does the application's Content Security Policy prevent exploitation? Weak CSP with unsafe-inline or unsafe-eval is trivially bypassed.
- DOM sources and sinks: Tools like DOM Invader (Burp Suite) map data flow from sources to dangerous sinks in client-side code.
Real-World Impact: Beyond alert(1)
Proof-of-concept XSS demonstrations with alert(1) dramatically undersell the actual risk. In production exploitation, XSS payloads:
- Steal session cookies and authentication tokens (bypassing MFA if session tokens are captured)
- Capture keystrokes to harvest credentials entered on the page
- Perform CSRF attacks as the authenticated victim
- Redirect victims to phishing sites or install browser-based malware
- In stored XSS scenarios: maintain persistent access to all visitors indefinitely until patched
Remediation: Content Security Policy and Output Encoding
Effective XSS remediation requires defense in depth. Output encoding — escaping HTML special characters (&, <, >, ", ') before rendering untrusted data — is the primary defense. Modern frameworks like React (JSX), Angular, and Vue automatically encode output; raw HTML injection methods (dangerouslySetInnerHTML in React, bypassSecurityTrustHtml in Angular) must be used only with sanitized content.
A strict Content Security Policy provides a second layer: Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none' prevents inline script execution even if XSS payloads are injected. Combined with output encoding, strict CSP reduces XSS exploitability dramatically. Our web application security assessments evaluate both encoding practices and CSP effectiveness across your entire application.
XSS in Single-Page Applications
SPAs introduce unique XSS vectors. Client-side routing with URL fragments, postMessage communication between origins, and JavaScript template literals used for DOM manipulation all create attack surface that traditional server-side testing misses. Tools like Burp Suite's DOM Invader and manual code review of client-side JavaScript are essential for comprehensive SPA assessment.
Angular applications with DomSanitizer.bypassSecurityTrustHtml(), React applications using dangerouslySetInnerHTML, and Vue applications with v-html directives are common sources of client-side XSS in modern applications. Any use of these APIs requires security review of the sanitization applied before the bypass call.