How does DOM-based XSS differ from reflected XSS?
Reflected XSS (Cross-Site Scripting) bounces the payload off the server (it's in the request and echoed into the response); DOM-based XSS never needs the server — client-side JS reads attacker input (e.g. the URL #fragment) and writes it unsafely into the page.
* Reflected XSS bounces the payload off the server; DOM-based XSS stays in the browser — client JS reads the URL fragment the server never receives. *
Reflected XSS:
- Payload sent to server in request
- Server includes payload in response
- Payload executes when response renders
DOM-based (Document Object Model) XSS:
- Payload possibly never reaches the server
- Can stay entirely in browser (e.g., URL fragment after
#) - Client-side JavaScript reads and unsafely uses the payload
Example DOM XSS:
// Vulnerable code
document.getElementById('content').innerHTML = location.hash.slice(1);
// Attack URL
https://site.com/page#<img src=x onerror=alert(document.cookie)>
The server sees a request for /page - the fragment isn't sent. But the JavaScript reads location.hash and injects it into the DOM.
Why this matters:
- Server-side WAF/filters don't see the payload
- Server logs show no evidence of attack
- Detection and prevention must happen client-side
Prevention: Sanitize data before DOM insertion. Use textContent instead of innerHTML. Implement Content Security Policy.
Go deeper:
PortSwigger — DOM-based XSS — the source→sink model; why the server never sees the payload.
Cross-site scripting (Wikipedia) — reflected, stored, and DOM-based XSS compared.