Skip to main content
Blog
Blog security

What Is DOM-Based XSS? How DOM Cross-Site Scripting Works

DOM-based XSS is a cross-site scripting attack where the vulnerability lives entirely in client-side JavaScript: the page's own code reads attacker-controlled input and writes it into the DOM unsafely. This guide explains how it differs from reflected and stored XSS, common sources and sinks, and how to detect it.

Aug 18, 2026 3 min read
What Is DOM-Based XSS? How DOM Cross-Site Scripting Works
Table of Contents

DOM-based XSS is a cross-site scripting vulnerability that lives entirely in client-side code. The page's own JavaScript reads attacker-controllable input — most often from the URL — and writes it into the DOM through an unsafe sink like innerHTML, executing the attacker's script. Unlike reflected or stored XSS, the malicious payload may never appear in any server response.

How does a DOM XSS attack work?

The vulnerability is a data flow from a source the attacker controls to a sink that interprets text as code or markup:

// vulnerable: fragment flows straight into a sink
const name = decodeURIComponent(location.hash.slice(1));
document.querySelector("#welcome").innerHTML = "Hello " + name;
// https://example.com/#<img src=x onerror=stealCookies()>

Common sources: location.hash, location.search, document.referrer, window.name, postMessage data, and client-side storage. Common sinks: innerHTML/outerHTML, document.write, eval and Function, jQuery's .html(), and attribute writes that create handlers or URLs (onclick, href with javascript:).

Because the URL fragment is never sent to the server, a payload after # can exploit the page while the server sees a perfectly normal request.

Reflected vs stored vs DOM-based XSS

Reflected XSSStored XSSDOM-based XSS
Where the payload livesIn the request, echoed by the serverIn the server's databaseIn client-side input (often the URL fragment)
Server response contains payload?Often ✗
Visible to WAFs / server logsUsuallyUsuallyOften not
Fixed whereServer-side output encodingServer-side sanitization + encodingClient-side code: safe sinks, sanitization

Why DOM XSS is easy to miss

Server-side defenses inspect requests and responses; DOM XSS can bypass both. Frameworks reduce the risk — React and friends escape by default — but dangerouslySetInnerHTML, template misuse, and the third-party scripts on the page reintroduce it. And a modern page runs dozens of scripts you did not write: an unsafe sink in any of them is an unsafe sink on your page. That composition problem is the core of client side security.

How to prevent and detect it

  • Prefer safe sinks: textContent over innerHTML; avoid eval and string-built handlers entirely.
  • Sanitize when HTML is unavoidable (DOMPurify or the emerging Sanitizer API), and adopt Trusted Types where supported — it turns unsafe sink writes into policy violations.
  • Deploy a strict Content Security Policy with nonces; it blocks many payload styles, though not the whole class.
  • Watch runtime behavior: exploitation ultimately manifests as scripts doing things they should not — new outbound requests, DOM writes into payment forms, unexpected listeners. cside's client-side monitoring observes real sessions at the browser layer, which is the only place a DOM-only attack is visible at all.
Simon Wijckmans
Founder & CEO

Founder and CEO of cside. Previously a product manager on Cloudflare Page Shield (now Cloudflare Client-Side Security). Co-chair of the W3C Anti-Fraud Community Group and a Forbes 30 Under 30 honoree. Building accessible security against client-side attacks, web security is not an enterprise-only problem.

FAQ

Frequently Asked Questions

In reflected XSS the malicious payload travels to the server and comes back embedded in the HTML response. In DOM-based XSS the server response can be completely clean: the page's own JavaScript reads the payload from a client-side source (often the URL fragment, which is never sent to the server) and injects it into the DOM. That is why server-side filters and WAFs, which inspect requests and responses, can miss DOM XSS entirely.

It helps but does not close the class. A strict Content Security Policy blocks inline script injection and untrusted sources, which defeats many payloads. But DOM XSS executed through an allowlisted script's own unsafe sink — or a payload that abuses a permitted framework feature — stays within policy. CSP is a strong layer; it is not a substitute for fixing unsafe sinks or watching what scripts actually do at runtime.

Statically, by auditing code paths from sources (location.hash, location.search, document.referrer, postMessage data) to sinks (innerHTML, document.write, eval, setAttribute of event handlers). Dynamically, with DOM-aware scanners and by monitoring real sessions for unexpected script behavior — the vulnerability only exists in the browser, so browser-layer visibility is where exploitation becomes observable.

Monitor and Secure Your Third-Party Scripts

Gain full visibility and control over every script delivered to your users to enhance site security and performance.

Start free, or try Business with a 14-day trial.

cside dashboard interface showing script monitoring and security analytics
Related Articles
Book a demo

Want to walk through this with an engineer?

Thirty minutes, on your own site. Not a slide deck.

We'll show you:

Which third-party scripts are running on your site right now
Where you stand on PCI DSS 6.4.3 and 11.6.1
How much of your traffic is bots and AI agents

Rather just send a question?

Finding open slots…

Real humans only. We'd know.

Having trouble booking? Open scheduler in a new tab

What are you trying to solve?

Tell us in a line and we'll come back with something useful, not a generic pitch.

We usually help with:

Seeing which third-party scripts run on your site
PCI DSS 6.4.3 and 11.6.1 evidence
Bots, AI agents and account takeover

Prefer to just book a time? Pick a slot instead