DOM-Based XSS: The Client-Side Threat
Understanding and defending against the stealthiest XSS variant
⚠️ Ethical Note: This guide is for educational purposes only. Only test systems you own or have permission to test.
What is DOM-Based XSS?
DOM-Based Cross-Site Scripting (XSS) is a client-side vulnerability where the attack payload is executed as a result of modifying the DOM (Document Object Model) environment in the victim’s browser. Unlike traditional XSS, the malicious payload never touches the server.
1
User visits malicious URL
Contains crafted parameters that affect DOM
Contains crafted parameters that affect DOM
2
Client-side script processes input
JavaScript writes attacker-controlled data to DOM
JavaScript writes attacker-controlled data to DOM
3
Malicious code executes
In the context of the vulnerable page
In the context of the vulnerable page
Key Differences from Other XSS Types
| Type | Payload Location | Server Involvement |
|---|---|---|
| Reflected XSS | Server response | Payload reflected from server |
| Stored XSS | Server database | Payload served from server |
| DOM-Based XSS | Client-side only | No server involvement |
How DOM-Based XSS Works
Vulnerable Code Example
// URL: https://example.com/page.html#default=<script>alert(1)</script>
const hash = window.location.hash.substring(1);
document.getElementById('message').innerHTML = hash;
Common Sources of DOM-Based XSS
document.URL/window.locationpropertiesdocument.referrerwindow.namelocalStorage/sessionStorage- HTML5 postMessage data
Finding DOM-Based XSS Vulnerabilities
1. Manual Testing Approach
- Identify DOM sinks (functions that write to DOM)
- Trace back to sources (user-controllable input)
- Test if sources flow to sinks without proper sanitization
2. Common Dangerous Sinks
element.innerHTML document.write() eval() setTimeout() location.href Function()
3. Testing Payloads
#test=<img src=x onerror=alert(1)> #default='-alert(1)-' #redirect=javascript:alert(document.domain)
Advanced DOM-Based XSS Techniques
1. AngularJS Sandbox Escapes
{{constructor.constructor('alert(1)')()}}
2. jQuery Selector Injection
#selector=<img src=x onerror=alert(1)>
3. PostMessage Exploitation
// Malicious page
window.opener.postMessage('<script>alert(1)</script>', '*');
// Vulnerable page
window.addEventListener('message', function(e) {
document.getElementById('content').innerHTML = e.data;
});
Tools for Detection
| Tool | Purpose | Usage |
|---|---|---|
| DOM Invader (Burp) | Built-in DOM XSS detection | Enable in Burp Browser |
| DOMinator Pro | Browser extension | Passive scanning |
| OWASP ZAP | DOM XSS active scan | Use DOM XSS scan rule |
| Manual Testing | Browser DevTools | Trace data flow |
Prevention and Mitigation
1. Safe DOM Manipulation
// UNSAFE element.innerHTML = userInput; // SAFE element.textContent = userInput; document.createTextNode(userInput);
2. Context-Aware Encoding
- HTML Context: Use
innerTextortextContent - Attribute Context: Escape quotes and special chars
- URL Context: Encode with
encodeURIComponent()
3. Content Security Policy (CSP)
Content-Security-Policy: script-src 'self'; object-src 'none';
Pro Tip: Use Trusted Types API (Chrome) to prevent unsafe DOM operations entirely.
Real-World Examples
Case 1: jQuery Selector Injection
A popular website used $(location.hash) allowing XSS through crafted hash fragments.
Case 2: AngularJS Client-Side Template
Single Page App evaluated user input as Angular expressions leading to RCE.
Case 3: PostMessage XSS
Chat widget trusted messages from any origin and injected them into DOM.
Conclusion
DOM-Based XSS is particularly dangerous because:
- It bypasses server-side protections
- Traditional scanners often miss it
- The attack happens entirely client-side
Remember: Always validate and sanitize all client-side input before DOM manipulation, regardless of server-side handling.