Home / Knowledge hub / DOM-based XSS
Knowledge hub
DOM-based XSS
Script injection that happens in the browser's own code, not in the server's response.
What it means
DOM-based XSS is a form of cross-site scripting where the unsafe step happens in the browser. Your page's own JavaScript takes data from an attacker-controlled source, such as the URL fragment or location.search, and writes it into a dangerous sink, such as innerHTML, document.write or eval.
The server may never see the payload. A fragment after # is not sent to the server at all, so the response looks clean and server-side filters and logs have nothing to catch. That is what separates it from reflected and stored cases.
Why it matters
A successful injection runs script in your origin with the visitor's session. It can read the page, make requests as that visitor and change what they see. For a single-page app the whole interface is built in the browser, so the exposure can be wide.
It is also easy to miss. Server-side scanners, a web firewall and code review of back-end templates all look in the wrong place. Modern front-end frameworks escape most output by default, so the problems tend to sit in the places where a developer chose to bypass that, for speed or for a rich-text feature.
How it shows up
You meet it in search boxes that update the page without a reload, in code that reads location.hash to pick a tab, in templates that build HTML from strings, and in third-party widgets. In frameworks, look for the escape hatches: dangerouslySetInnerHTML in React, v-html in Vue, bypassSecurityTrust in Angular.
Fixes follow one rule: put untrusted data into the page as text, not as markup. Use textContent, not innerHTML. Where HTML is needed, sanitise it with a maintained library. Add Trusted Types and a content security policy as a second layer, not as the first.
Questions people ask
DOM-based XSS, answered
How is DOM-based XSS different from reflected XSS?
In reflected XSS the server puts the input into its response. In the DOM case the browser-side code does it, so the server may never see the payload. The effect on the visitor is the same.
Can a web application firewall stop DOM XSS?
Rarely. If the payload sits in the URL fragment, it never reaches the firewall. Fix the code that writes the data into the page instead.
What are sources and sinks?
A source is where untrusted data enters browser code, such as the URL, document.referrer or postMessage. A sink is a function that turns data into code or markup. DOM XSS needs a path from one to the other.
Does using React or Vue make us safe?
It makes the common case safe, because output is escaped by default. Risk returns where you use raw-HTML features, build URLs from user input, or pass data to eval-like functions.
How do we test for it?
Review the front-end code for risky sinks, and test in a real browser with payloads in the URL, fragment and stored values. Static reading finds candidates; execution in a browser proves which ones fire.
Related
Terms that sit next to this one
XSS
An attacker's script running in your pages, in your customers' sessions.
Reflected XSS
A script in a link that your page echoes straight back into the response.
Stored XSS
Malicious script saved by your app and then served to other people who view it.
Content Security Policy
A header telling the browser which scripts a page may load.
Input validation
Checking that what arrives is the shape and range you expected.
Does the script run in a real browser?
We drive the running app in a browser and, in white-box mode, read the code to point to the line, so a DOM XSS finding is one that actually fired. Book a pilot on one app.
Or start with a $199 pilot on one application: thirty days, success criteria agreed before day one, credited against the annual if you convert.