What Is DOM-Based XSS
DOM-based Cross-Site Scripting (DOM XSS) is a client-side injection vulnerability where malicious JavaScript executes entirely within the browser. Unlike reflected or stored XSS, the malicious payload never reaches the server. Instead, the page's own JavaScript reads attacker-controlled data from the browser environment and writes it into the DOM in an unsafe way.
Classified under CWE-79 and OWASP A03:2021 – Injection, DOM XSS exploits the growing complexity of client-side applications. As single-page applications (SPAs) handle more logic in the browser, the attack surface for DOM XSS has expanded significantly.
The defining characteristic of DOM XSS is that the vulnerability exists in the client-side code itself. The server delivers a legitimate page, but the JavaScript on that page processes user input unsafely. This means the attack bypasses server-side sanitization, WAFs, and traditional output encoding because the dangerous operation happens after the server has finished its response.
DOM XSS can steal session tokens, redirect users to phishing pages, inject fake login forms, or modify page content—all without triggering any server-side logging or detection.
Sources and Sinks in DOM XSS
DOM XSS follows a source-to-sink data flow. A source is where attacker-controlled data enters the JavaScript execution context. A sink is a DOM API that executes or renders that data in a dangerous way.
Common Sources
document.location,location.hash,location.search– URL components the attacker controls via crafted linksdocument.referrer– the referring page URLwindow.name– persists across navigations, controllable by the openerpostMessagedata – messages from other windows or iframes without origin validationdocument.cookie– when cookies are set by attacker-controlled subdomains
Dangerous Sinks
element.innerHTMLandelement.outerHTML– parse and render HTML including script tags and event handlersdocument.write()anddocument.writeln()– inject raw HTML into the document streameval(),setTimeout(string),new Function()– execute arbitrary JavaScript from strings
When data flows from a source to a sink without sanitization, the attacker's payload executes as trusted JavaScript:
// Source: URL hash (attacker-controlled)
const userInput = window.location.hash.substring(1);
// Sink: innerHTML (renders HTML)
document.getElementById('content').innerHTML = userInput;
// Attack URL: https://example.com/page#<img src=x onerror=alert(document.cookie)>
In React applications, dangerouslySetInnerHTML acts as the equivalent sink, bypassing React's default escaping.
Why Server-Side Protections Fail
Traditional security measures target server-side vulnerabilities. DOM XSS bypasses all of them because the payload never appears in an HTTP request to the server:
- Web Application Firewalls (WAFs) inspect HTTP requests and responses. DOM XSS payloads in URL fragments (
#) are never sent to the server, so WAFs never see them. - Server-side output encoding escapes data before rendering HTML responses. DOM XSS occurs after the server response is delivered, in client-side JavaScript that manipulates the DOM directly.
- Server-side input validation sanitizes request parameters. URL fragments,
postMessagedata, andwindow.nameare never part of the server request. - Server logs do not capture DOM XSS attacks. The fragment identifier is stripped by the browser before sending the request, making these attacks invisible to monitoring.
This invisibility makes DOM XSS particularly dangerous in compliance-sensitive environments. Attacks leave no server-side evidence, complicating forensic analysis and incident response. The only effective defense is analyzing client-side JavaScript for unsafe source-to-sink data flows before the code reaches production.
How CodeSlick Detects DOM XSS
CodeSlick identifies DOM XSS patterns in JavaScript and TypeScript by detecting unsafe sink usage with dynamic input:
- innerHTML and outerHTML assignments with template literals, string concatenation, or variable input—static strings and sanitized values (e.g., DOMPurify) are excluded to reduce false positives
- document.write() and document.writeln() calls with dynamic content
- React dangerouslySetInnerHTML with unsanitized data and unsafe
hrefattributes containingjavascript:protocols - Missing Content-Security-Policy headers that would mitigate XSS impact
All findings include CWE-79 classification, CVSS severity scoring, and OWASP A03 mapping. CodeSlick's AI-powered fix engine generates properly escaped alternatives using textContent, DOMPurify sanitization, or framework-appropriate patterns.
Scan your JavaScript and TypeScript code for DOM XSS vulnerabilities in under 3 seconds.