DOM-Based Cross-Site Scripting (XSS)
Client-side JavaScript writes untrusted data into the DOM, executing attacker scripts without the server ever seeing the payload.
What is DOM-Based Cross-Site Scripting (XSS)?
DOM-based XSS happens entirely in the browser. JavaScript reads attacker-controlled "sources" — location.hash, location.search, document.referrer, postMessage events, window.name — and passes them into dangerous "sinks": innerHTML, document.write, eval, setTimeout with strings, or jQuery's \$().html(). Because the malicious data never travels to the server, server-side logs see nothing, and WAFs that inspect requests have nothing to match — the payload can live after the # in the URL, which browsers do not even send to servers. Single-page applications with client-side routing are the natural habitat: hash-based routing, query-string handling, and dynamic rendering multiply the source-to-sink paths.
Why It Matters to Your Business
The impact is identical to other XSS — session theft, keylogging, actions performed as the victim, trusted-domain phishing — but detection is harder, so DOM XSS survives longer in production. Payloads delivered via the URL fragment bypass server logs entirely, meaning incidents are often discovered late. For SPAs, one vulnerable sink can affect the whole application because the attacker controls the data before, during, and after client-side rendering.
How to Fix It
1. Map your sources and sinks. Dangerous sources: location.hash/search, document.referrer, postMessage, window.name. Dangerous sinks: innerHTML, outerHTML, insertAdjacentHTML, document.write, eval, new Function, setTimeout/setInterval with strings, element.setAttribute('href'|'src', ...), location assignments.
2. Prefer safe APIs — for rendering text:
el.textContent = userInput; // SAFE
el.innerHTML = userInput; // DANGEROUS
3. When HTML must be rendered, sanitize with DOMPurify:
el.innerHTML = DOMPurify.sanitize(userInput);
4. Never pass untrusted strings to eval / new Function / setTimeout-as-string.
5. Framework notes: React JSX and Angular {{ }} escape by default — the risk is dangerouslySetInnerHTML, v-html, [innerHTML]. jQuery: $(el).text() not $(el).html().
6. Enforce Trusted Types (Content-Security-Policy: require-trusted-types-for 'script') — the browser then blocks any sink call with a plain string, catching what reviews miss.
7. Validate postMessage origins: always check event.origin before using event.data.
Frequently Asked Questions
Why does my WAF not catch DOM-based XSS?
Because the attack never reaches the WAF. The payload can live in the URL fragment (#...) which browsers do not transmit to the server at all — the malicious data flows from the URL to JavaScript to the DOM entirely inside the victim's browser.
What are sources and sinks in DOM XSS?
Sources are places attacker data can enter: location.hash, search parameters, document.referrer, postMessage. Sinks are APIs that execute or render: innerHTML, eval, document.write. DOM XSS = an unvalidated path from a source to a sink.
How do I test my application for DOM XSS?
Use client-side analysis (headless scanning catches source-to-sink paths — our DOM scanners do this), plus code review of every innerHTML/eval call, plus Trusted Types in report-only mode to surface violations in production safely.
Technical Classification
| OWASP Category | A03:2021 — Injection |
| CWE ID | CWE-79: Improper Neutralization of Input During Web Page Generation |
| Detected By | dom_hygiene, client_path_taint, dalfox_xss scanner(s) |
| Severity Level | high |
How 2MNY Security Can Help
Check if your website has this vulnerability
Our dom_hygiene, client_path_taint, dalfox_xss scanner checks for this issue automatically.
Scan My Website FreeRelated Vulnerabilities
Open Redirect Vulnerability
The site has an open redirect — a parameter that redirects to any URL, allowing phishing campaigns that appear to come from your domain.
Dangerous HTTP Methods Enabled
The server allows dangerous HTTP methods (PUT, DELETE, TRACE, CONNECT, WebDAV) that can be abused for file upload, deletion, or cross-site tracing.
SQL Injection (Reflected) Vulnerability
Unvalidated user input flows into database queries, letting attackers read your data or take over the server.
Reflected Cross-Site Scripting (XSS)
User input is echoed into pages unescaped, so crafted links run attacker JavaScript in your visitors' browsers.