DOM-Based XSS
What is DOM-Based XSS?
DOM-Based XSS (Document Object Model Cross-Site Scripting) is a client-side vulnerability where malicious scripts execute due to unsafe manipulation of the DOM environment by JavaScript code. Unlike stored or reflected XSS, DOM-Based XSS occurs entirely in the browser without any server-side reflection of the payload.
Key Characteristics
- Client-side execution: Vulnerability exists in JavaScript code
- No server reflection: Payload never reaches the server
- DOM manipulation: Exploits unsafe handling of DOM elements
- Source-sink model: Requires both a source and a sink
- Modern web apps: Particularly prevalent in SPAs and dynamic websites
How DOM-Based XSS Works
Attack Flow
graph TD
A[Attacker] -->|1. Crafts malicious URL| B[Victim]
B -->|2. Clicks link| C[Web Application]
C -->|3. Loads page| B
B -->|4. Browser executes JavaScript| B
B -->|5. DOM manipulation with malicious input| B
B -->|6. Script executes| D[Malicious actions]
D -->|7. Sends data| A
Technical Mechanism
- Source Identification: Attacker finds a DOM source that accepts user input
- Sink Identification: Attacker finds a DOM sink that executes code
- Payload Crafting: Attacker creates payload that flows from source to sink
- Delivery: Attacker tricks victim into visiting malicious URL
- Execution: Victim's browser executes the malicious script
- Exploitation: Attacker achieves malicious objectives
Source-Sink Model
| Sources (User Input) | Sinks (Dangerous Functions) |
|---|---|
document.URL | element.innerHTML |
document.location | document.write() |
document.referrer | document.writeln() |
window.location | eval() |
window.name | setTimeout() |
history.pushState() | setInterval() |
localStorage | Function() constructor |
sessionStorage | location.href assignment |
postMessage data | location.replace() |
URL fragments (#) | location.assign() |
DOM-Based XSS Attack Vectors
Common Injection Points
| Vector | Description | Example |
|---|---|---|
| URL Fragments | Data after # in URL | https://example.com/#<img src=x onerror=alert(1)> |
| URL Parameters | Query string parameters | https://example.com/?search=<script>alert(1)</script> |
| Document Properties | document.location, document.URL | Malicious data in window.location.hash |
| Web Storage | localStorage, sessionStorage | Stored malicious scripts in web storage |
| PostMessage | Cross-window messaging | Malicious data in event.data |
| JSON Data | Client-side JSON processing | Unsafe parsing of JSON with user data |
| Third-party Scripts | External JavaScript libraries | Vulnerable jQuery plugins |
| Dynamic Content | Client-side templating | Unsafe interpolation in templates |
Real-World Examples
- Single-Page Applications: Vulnerable routing implementations
- Social Media Widgets: Unsafe handling of URL parameters
- Analytics Libraries: Unsafe processing of referrer data
- Advertising Scripts: Unsafe DOM manipulation
- Browser Extensions: Unsafe content script execution
- Progressive Web Apps: Unsafe service worker handling
DOM-Based XSS Exploitation Techniques
1. Basic DOM XSS
Vulnerable Code:
// Unsafe handling of URL fragment
const userInput = window.location.hash.substring(1);
document.getElementById('content').innerHTML = userInput;
Malicious URL:
https://example.com/#<img src=x onerror=alert('DOM XSS')>
Process:
- Attacker crafts URL with malicious fragment
- Victim clicks link
- Browser loads page and executes JavaScript
- JavaScript extracts fragment and inserts into DOM
- Malicious script executes
2. Location-Based XSS
Vulnerable Code:
// Unsafe handling of URL parameters
const searchTerm = new URLSearchParams(window.location.search).get('q');
document.write('<h1>Results for: ' + searchTerm + '</h1>');
Malicious URL:
https://example.com/search?q=<script>alert('XSS')</script>
Process:
- Attacker crafts URL with malicious parameter
- Victim clicks link
- Browser loads page and executes JavaScript
- JavaScript extracts parameter and writes to DOM
- Malicious script executes
3. Web Storage XSS
Vulnerable Code:
// Unsafe handling of localStorage data
const userTheme = localStorage.getItem('theme');
document.getElementById('theme').innerHTML = userTheme;
Exploitation:
// Attacker sets malicious theme
localStorage.setItem('theme', '<img src=x onerror=alert("XSS")>');
// Victim visits page and script executes
Process:
- Attacker sets malicious data in localStorage
- Victim visits page
- JavaScript retrieves data from localStorage
- Data is inserted into DOM
- Malicious script executes
4. PostMessage XSS
Vulnerable Code:
// Unsafe handling of postMessage data
window.addEventListener('message', function(event) {
document.getElementById('output').innerHTML = event.data;
});
Exploitation:
// Attacker sends malicious message
targetWindow.postMessage('<img src=x onerror=alert("XSS")>', '*');
Process:
- Attacker opens target window
- Attacker sends malicious postMessage
- Victim's page receives message
- JavaScript inserts message data into DOM
- Malicious script executes
5. jQuery XSS
Vulnerable Code:
// Unsafe jQuery DOM manipulation
const userInput = window.location.hash.substring(1);
$(userInput).appendTo('#content');
Malicious URL:
https://example.com/#<img src=x onerror=alert('jQuery XSS')>
Process:
- Attacker crafts URL with malicious fragment
- Victim clicks link
- jQuery parses and executes the HTML
- Malicious script executes
DOM-Based XSS Prevention
1. Safe DOM Manipulation
Principle: Use safe methods for DOM manipulation.
Safe Methods:
- textContent: For text insertion (escapes HTML)
- setAttribute: For attribute setting
- document.createElement: For element creation
- element.appendChild: For safe DOM insertion
Example (Safe DOM Manipulation):
// Safe text insertion
const userInput = window.location.hash.substring(1);
document.getElementById('content').textContent = userInput;
// Safe HTML insertion with DOMPurify
const clean = DOMPurify.sanitize(userInput);
document.getElementById('content').innerHTML = clean;
// Safe attribute setting
const img = document.createElement('img');
img.setAttribute('src', safeUrl);
document.body.appendChild(img);
2. Input Validation
Principle: Validate all user input before processing.
Techniques:
- Allowlists: Only allow known-good patterns
- Type checking: Validate data types
- Length restrictions: Limit input length
- Format validation: Validate URLs, emails, etc.
Example (Input Validation):
// Validate URL fragment
function isValidFragment(fragment) {
// Allow only alphanumeric and basic punctuation
return /^[a-zA-Z0-9\s\-_,.!?'"()]{1,100}$/.test(fragment);
}
// Validate URL parameter
function isValidSearchQuery(query) {
// Allow only safe characters
return /^[a-zA-Z0-9\s\-_]{1,50}$/.test(query);
}
3. Output Encoding
Principle: Encode data before inserting into DOM.
Context-Specific Encoding:
- HTML context: HTML entity encoding
- JavaScript context: JavaScript string encoding
- URL context: URL encoding
- CSS context: CSS encoding
Example (Output Encoding):
// HTML encoding
function htmlEncode(str) {
return str.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
// JavaScript encoding
function jsEncode(str) {
return JSON.stringify(str);
}
// URL encoding
function urlEncode(str) {
return encodeURIComponent(str);
}
4. Content Security Policy (CSP)
Principle: Restrict sources of executable scripts.
Effective CSP for DOM XSS:
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-eval' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-src 'none'; object-src 'none'; base-uri 'self'; form-action 'self'
Key Directives:
- script-src: Restrict JavaScript sources
- style-src: Restrict CSS sources
- img-src: Restrict image sources
- connect-src: Restrict API calls
- frame-src: Prevent iframe usage
- object-src: Prevent plugin content
- base-uri: Restrict base URL
5. Trusted Types
Principle: Use modern browser API to prevent DOM XSS.
Implementation:
// Enable Trusted Types
if (window.trustedTypes && trustedTypes.createPolicy) {
const policy = trustedTypes.createPolicy('default', {
createHTML: string => DOMPurify.sanitize(string),
createScriptURL: string => {
// Validate script URLs
if (isTrustedScriptUrl(string)) {
return string;
}
throw new Error('Untrusted script URL');
},
createScript: string => {
// Validate scripts
if (isTrustedScript(string)) {
return string;
}
throw new Error('Untrusted script');
}
});
}
// Use Trusted Types
const userInput = window.location.hash.substring(1);
const trustedHtml = policy.createHTML(userInput);
document.getElementById('content').innerHTML = trustedHtml;
6. Secure Coding Practices
Best Practices:
- Never use innerHTML: Prefer textContent or safe DOM methods
- Avoid document.write: Use modern DOM manipulation methods
- Validate all inputs: Even from "trusted" sources
- Use safe libraries: Like DOMPurify for HTML sanitization
- Implement CSP: Content Security Policy
- Use HttpOnly cookies: Prevent JavaScript access to cookies
- Regular security testing: Identify and fix vulnerabilities
Example (Secure jQuery):
// Safe jQuery usage
const userInput = window.location.hash.substring(1);
$('#content').text(userInput); // Safe: uses text() instead of html()
// Or with sanitization
const clean = DOMPurify.sanitize(userInput);
$('#content').html(clean);
DOM-Based XSS in Modern Web Applications
Single-Page Applications (SPAs)
Challenges:
- Client-side routing: Vulnerable to parameter-based attacks
- Dynamic content loading: Increased attack surface
- State management: Complex data flow
- API communication: Potential injection points
Prevention:
- Use framework protections: React, Vue, Angular have built-in protections
- Implement CSP: Restrict script sources
- Validate route parameters: Sanitize all URL parameters
- Secure API endpoints: Validate all API inputs
Example (React):
import { useLocation } from 'react-router-dom';
import DOMPurify from 'dompurify';
function SearchResults() {
const location = useLocation();
const searchParams = new URLSearchParams(location.search);
const query = searchParams.get('q');
// Validate and sanitize input
const safeQuery = query ? DOMPurify.sanitize(query) : '';
return (
<div>
<h1>Search Results for: {safeQuery}</h1>
{/* Safe: React automatically escapes content */}
</div>
);
}
APIs and Microservices
Challenges:
- JSON responses: Potential for XSS in API consumers
- Client-side processing: Unsafe handling of API data
- Dynamic content: Client-side templating vulnerabilities
Prevention:
- Validate API responses: Even from trusted services
- Encode API data: Before inserting into DOM
- Implement CSP: Restrict script sources
- Use safe parsing: For JSON and other data formats
Example (Secure API Handling):
// Secure API data handling
async function loadUserData() {
const response = await fetch('/api/user');
const data = await response.json();
// Validate and encode data
const safeName = htmlEncode(data.name);
const safeBio = htmlEncode(data.bio);
// Safe DOM insertion
document.getElementById('name').textContent = safeName;
document.getElementById('bio').textContent = safeBio;
}
Serverless Applications
Challenges:
- Function inputs: Potential injection vectors
- Event sources: XSS through event data
- Third-party services: Increased attack surface
- Client-side logic: More complex DOM manipulation
Prevention:
- Validate function inputs: Never trust event data
- Secure client-side code: Follow secure coding practices
- Implement CSP: For serverless web applications
- Monitor execution: Detect suspicious activity
Example (AWS Lambda with Client-Side Security):
// Client-side code for serverless app
async function loadData() {
const params = new URLSearchParams(window.location.search);
const id = params.get('id');
// Validate input
if (!/^\d+$/.test(id)) {
throw new Error('Invalid ID');
}
const response = await fetch(`/api/data?id=${encodeURIComponent(id)}`);
const data = await response.json();
// Safe DOM insertion
document.getElementById('title').textContent = htmlEncode(data.title);
document.getElementById('content').textContent = htmlEncode(data.content);
}
DOM-Based XSS Testing and Detection
Manual Testing Techniques
- Basic Test:
#<img src=x onerror=alert('DOM XSS')> - URL Parameter Test:
?q=<script>alert('DOM XSS')</script> - JavaScript URI Test:
javascript:alert('DOM XSS') - Event Handler Test:
#<body onload=alert('DOM XSS')> - jQuery Test:
#<img src=x onerror=alert('jQuery XSS')> - Web Storage Test:
localStorage.setItem('test', '<img src=x onerror=alert("XSS")>'); - PostMessage Test:
window.postMessage('<img src=x onerror=alert("XSS")>', '*');
Automated Testing Tools
- DOM Invader: Browser extension for DOM XSS testing
- Burp Suite: Web application security testing platform
- OWASP ZAP: Zed Attack Proxy for vulnerability scanning
- XSStrike: Advanced XSS detection suite
- DOMXSS Scanner: Specialized DOM XSS scanner
- Lighthouse: Can detect some DOM XSS issues
- ESLint: Static analysis for JavaScript security
Browser Developer Tools
- Elements Inspector: Check DOM manipulation
- Console: Test JavaScript execution
- Debugger: Step through JavaScript code
- Sources Tab: Analyze JavaScript files
- Event Listeners: Check for unsafe event handling
- Local Storage: Inspect web storage content
Code Analysis Techniques
- Source-Sink Analysis: Identify dangerous data flows
- Taint Tracking: Track user input through code
- Static Analysis: Analyze code without execution
- Dynamic Analysis: Test running code
- Fuzz Testing: Automated input testing
DOM-Based XSS Case Studies
Case Study 1: Social Media Widget Vulnerability
Incident: A popular social media widget had a DOM-Based XSS vulnerability.
Attack Details:
- Widget used
document.location.hashto store user preferences - Unsafe handling of hash data with
innerHTML - Attacker crafted malicious URLs with XSS payloads
- Payload executed when users visited pages with the widget
- Attack affected millions of websites using the widget
Impact:
- Massive XSS worm potential
- Data theft from affected websites
- Reputational damage to widget provider
- Costly remediation for all affected sites
- Regulatory scrutiny
Lessons Learned:
- Critical importance of safe DOM manipulation
- Need for Content Security Policy (CSP)
- Value of secure coding practices in libraries
- Importance of third-party code review
- Need for automated security testing
Case Study 2: Single-Page Application Exploitation
Incident: A major SPA framework had a DOM-Based XSS vulnerability.
Attack Details:
- Framework used client-side routing with URL parameters
- Unsafe handling of route parameters in templates
- Attacker crafted malicious URLs with XSS payloads
- Payload executed when users visited specific routes
- Attack affected thousands of applications
Impact:
- Widespread XSS vulnerabilities
- Data theft from affected applications
- Framework reputation damage
- Costly patches and updates
- Developer education requirements
Lessons Learned:
- Importance of secure routing in SPAs
- Need for framework-level protections
- Value of automatic escaping in templates
- Importance of security-focused development
- Need for responsible disclosure
Case Study 3: Browser Extension Compromise
Incident: A popular browser extension had a DOM-Based XSS vulnerability.
Attack Details:
- Extension used
localStorageto store user data - Unsafe handling of stored data with
innerHTML - Attacker crafted malicious web pages that set malicious data
- Payload executed when extension rendered content
- Attack affected millions of extension users
Impact:
- Massive user data exposure
- Extension reputation damage
- Browser security concerns
- Regulatory investigations
- Costly incident response
Lessons Learned:
- Critical importance of secure storage handling
- Need for Content Security Policy (CSP) in extensions
- Value of sandboxing in browser extensions
- Importance of secure coding practices
- Need for regular security audits
DOM-Based XSS and Compliance
Regulatory Implications
DOM-Based XSS vulnerabilities can lead to compliance violations with various regulations:
- GDPR: General Data Protection Regulation
- Requires protection of personal data
- Mandates data breach notification
- Imposes significant fines for non-compliance
- PCI DSS: Payment Card Industry Data Security Standard
- Requires protection of cardholder data
- Mandates secure coding practices
- Requires regular vulnerability scanning
- HIPAA: Health Insurance Portability and Accountability Act
- Requires protection of health information
- Mandates security risk assessments
- Requires implementation of security measures
- FISMA: Federal Information Security Management Act
- Requires security controls for government systems
- Mandates risk assessments
- Requires continuous monitoring
- CCPA: California Consumer Privacy Act
- Requires protection of consumer data
- Mandates data access and deletion rights
- Imposes fines for data breaches
Compliance Requirements
| Regulation | Requirement | DOM-Based XSS Prevention |
|---|---|---|
| GDPR | Protect personal data | Secure coding, CSP, input validation |
| PCI DSS | Protect cardholder data | Secure coding, regular testing, CSP |
| HIPAA | Protect health information | Secure development, input validation |
| FISMA | Secure government systems | Risk assessments, security controls |
| CCPA | Protect consumer data | Secure coding, data protection measures |
DOM-Based XSS in the OWASP Top 10
OWASP Top 10 2021: DOM-Based XSS is part of A03:2021 - Injection, which is ranked #3 in the OWASP Top 10 Web Application Security Risks.
Key Points:
- Prevalence: DOM-Based XSS is increasingly common in modern web apps
- Exploitability: Can be exploited without server interaction
- Impact: Can lead to account takeover, data theft, malware distribution
- Detectability: Harder to detect than server-side XSS
- Business Impact: Can cause significant reputational and financial damage
OWASP Recommendations:
- Use frameworks that automatically escape XSS
- Implement Content Security Policy (CSP)
- Use Trusted Types for DOM manipulation
- Validate all inputs on the client side
- Encode all outputs before DOM insertion
- Regular security testing to identify vulnerabilities
- Educate developers on secure coding practices
- Implement defense in depth with multiple security layers
Advanced DOM-Based XSS Techniques
1. Mutation XSS
Technique: Exploits browser parsing quirks to bypass filters.
Example:
<!-- Bypasses simple filtering -->
<img src=x onerror="alert('XSS')//">
<!-- Uses malformed HTML -->
<svg><script>alert('XSS')</script></svg>
<!-- Uses Unicode encoding -->
<iframe src="javascript:alert('XSS')">
Prevention:
- Use context-aware encoding
- Implement multiple layers of filtering
- Use modern HTML parsers
- Test with multiple browsers
2. Prototype Pollution
Technique: Exploits JavaScript prototype inheritance to inject malicious code.
Example:
// Vulnerable code
const user = JSON.parse('{"__proto__": {"isAdmin": true}}');
if (user.isAdmin) {
// Malicious code execution
}
// DOM XSS via prototype pollution
Object.prototype.innerHTML = '<img src=x onerror=alert("XSS")>';
Prevention:
- Freeze Object.prototype:
Object.freeze(Object.prototype) - Use safe JSON parsing: Avoid parsing untrusted JSON
- Validate object properties: Check for prototype properties
- Use Map instead of objects: For user data storage
3. Web Components XSS
Technique: Exploits custom web components to execute XSS.
Example:
// Vulnerable custom element
class UserCard extends HTMLElement {
connectedCallback() {
this.innerHTML = this.getAttribute('data-user');
}
}
customElements.define('user-card', UserCard);
// Malicious usage
<user-card data-user="<img src=x onerror=alert('XSS')>"></user-card>
Prevention:
- Sanitize attributes: Before using in innerHTML
- Use textContent: Instead of innerHTML when possible
- Validate component inputs: Before processing
- Implement CSP: Restrict script sources
4. Shadow DOM XSS
Technique: Exploits shadow DOM to bypass security controls.
Example:
// Vulnerable shadow DOM usage
const shadow = element.attachShadow({mode: 'open'});
shadow.innerHTML = userInput; // Unsafe
Prevention:
- Sanitize content: Before inserting into shadow DOM
- Use textContent: Instead of innerHTML
- Implement CSP: Even for shadow DOM
- Validate inputs: Before shadow DOM insertion
5. WebAssembly XSS
Technique: Uses WebAssembly to execute malicious code.
Example:
// Load malicious WebAssembly
WebAssembly.instantiateStreaming(fetch('malicious.wasm'))
.then(obj => {
// Execute malicious code
obj.instance.exports.main();
});
Prevention:
- Restrict WebAssembly sources: With CSP
- Validate WebAssembly modules: Before loading
- Sandbox execution: Limit WebAssembly capabilities
- Monitor WebAssembly usage: Detect suspicious activity
DOM-Based XSS Mitigation Strategies
Defense in Depth Approach
- Input Layer:
- Validate all user input
- Sanitize input before processing
- Use allowlists for expected input
- Processing Layer:
- Use safe DOM manipulation methods
- Implement proper encoding for all contexts
- Use security-focused libraries
- Output Layer:
- Encode all output before DOM insertion
- Implement Content Security Policy
- Use Trusted Types
- Client Layer:
- Implement browser security features
- Use modern frameworks with built-in protections
- Educate users about security risks
- Monitoring Layer:
- Monitor for suspicious activity
- Implement rate limiting
- Detect and block malicious requests
Secure Development Lifecycle
- Design Phase:
- Threat modeling for DOM XSS risks
- Security requirements definition
- Secure architecture design
- Development Phase:
- Secure coding practices
- Code reviews with security focus
- Static application security testing (SAST)
- Testing Phase:
- Dynamic application security testing (DAST)
- Penetration testing
- Vulnerability scanning
- Manual security testing
- Deployment Phase:
- Secure configuration
- Security headers implementation
- Content Security Policy deployment
- Web Application Firewall (WAF) configuration
- Maintenance Phase:
- Regular security updates
- Patch management
- Security monitoring
- Incident response planning
- User education
Emerging Technologies
- Trusted Types:
- Modern API to prevent DOM XSS
- Enforces safe DOM manipulation
- Requires explicit trust for dangerous operations
- Subresource Integrity (SRI):
- Ensures integrity of loaded resources
- Prevents tampering with external scripts
- Uses cryptographic hashes to verify content
- WebAssembly:
- Sandboxed execution environment
- Can be used for security-sensitive operations
- Reduces attack surface for XSS
- Isolated Components:
- Shadow DOM for encapsulation
- Web Components for secure UI elements
- Iframe sandboxing for isolation
- Automatic Escaping:
- Modern frameworks with built-in escaping
- Context-aware automatic encoding
- Reduced developer burden
Conclusion
DOM-Based XSS represents a significant evolution in cross-site scripting vulnerabilities, shifting the attack surface from server-side to client-side code. As modern web applications increasingly rely on JavaScript frameworks, single-page architectures, and dynamic content loading, DOM-Based XSS has become one of the most prevalent and challenging web security threats.
The unique characteristics of DOM-Based XSS make it particularly dangerous:
- No server interaction: Payload never reaches the server
- Hard to detect: Traditional security tools often miss client-side vulnerabilities
- Framework agnostic: Affects all JavaScript frameworks
- Persistent potential: Can be stored in web storage or other client-side mechanisms
- Evasive: Can bypass many traditional security controls
Preventing DOM-Based XSS requires a comprehensive, multi-layered approach that includes:
- Safe DOM manipulation: Using secure methods like
textContent - Input validation: Validating all user-supplied data
- Output encoding: Encoding data before DOM insertion
- Content Security Policy (CSP): Restricting script sources
- Trusted Types: Modern API for safe DOM operations
- Secure coding practices: Following security guidelines
- Regular testing: Identifying and fixing vulnerabilities
- Developer education: Training on client-side security
As web technologies continue to evolve with WebAssembly, Web Components, and advanced JavaScript frameworks, the threat landscape for DOM-Based XSS will continue to expand. Developers and security professionals must stay vigilant and implement comprehensive security measures to protect against these sophisticated attacks.
The key to effective DOM-Based XSS prevention lies in secure development practices, continuous monitoring, proactive security testing, and a defense-in-depth approach that adapts to evolving threats in the modern web landscape. By understanding the mechanisms, techniques, and prevention methods of DOM-Based XSS, organizations can significantly reduce their risk and protect their users from these pervasive and damaging attacks.
DNSSEC (DNS Security Extensions)
A suite of extensions to DNS that provides cryptographic authentication of DNS data, preventing spoofing and cache poisoning attacks.
Domain Fronting
A technique that hides the true destination of internet traffic by routing it through legitimate, high-reputation domains to bypass censorship or surveillance.
