DOM-Based XSS
DOM-based XSS occurs when client-side JavaScript reads attacker-controlled data and writes it to the DOM in a way the browser executes as script. The server response may be entirely free of the payload. The vulnerability is in JavaScript running in the browser, not in the server-side code.
Sources
A source is a JavaScript property that contains attacker-controlled data. Common sources:
location.hash: the fragment portion of the URL after#. Browsers do not send the fragment to the server, so server-side analysis cannot detect payloads placed here.location.search: the query string. The server does receive this, but DOM-based XSS using the query string as a source is still client-side if the JavaScript reads and uses it directly.document.referrer: the URL of the page that linked to the current one.window.name: a property that persists across navigation within a browser tab, settable from other pages.- Data from
postMessageevents when the receiver does not validate the origin.
Sinks
A sink is a JavaScript function or property that, when given attacker-controlled data, causes script execution. Common dangerous sinks:
element.innerHTML: assigns raw HTML to an element. Browsers parse and render the HTML, including script elements and event attributes.document.write(): writes raw HTML into the document during or after loading.eval(): evaluates a string as JavaScript.setTimeout()andsetInterval()when called with a string argument rather than a function reference.element.srcandelement.hrefwhen set to ajavascript:URL.location.hrefwhen set to attacker-controlled input that begins withjavascript:.
A Concrete Case
A single-page application reads the fragment to populate a greeting:
const name = location.hash.slice(1);
document.getElementById('greeting').innerHTML = 'Hello, ' + name;
A URL with fragment #<img src=x onerror=alert(1)> causes the script to assign that string to innerHTML. The browser parses an <img> element with an onerror handler and fires the handler when the image fails to load. The entire flow is client-side. The server logs a request with no indication of the payload.
Why DOM-Based XSS Is Harder to Find
Server-side code review and HTTP-level scanning tools can find reflected and stored XSS by tracing request parameters through server templates. DOM-based XSS requires analyzing JavaScript execution paths: which sources flow into which sinks, and whether any sanitization occurs in between. This requires either static analysis of JavaScript or dynamic analysis through a browser. Automated scanners miss many DOM XSS cases because they do not execute JavaScript or do not trace data flow through it.
Code search for dangerous sinks (innerHTML, eval, document.write) is a starting point. Each sink should be reviewed to determine what data reaches it and whether that data can be controlled from a URL or other external source.