BIPI
BIPI

DOM Clobbering: From HTMLCollection Tricks to RCE on Modern Apps

Cybersecurity

DOM Clobbering is older than the web but it keeps landing in modern bug bounties. We cover named element collection abuse, namespace pollution, prototype pollution chains, and how it cascades into XSS and code execution.

By Arjun Raghavan, Security & Systems Lead, BIPI · December 11, 2023 · 9 min read

#dom-clobbering#xss#prototype-pollution#pentesting#browser

The core trick

Browsers expose named HTML elements on document and window. A form named config becomes document.config. If JavaScript later reads window.config and uses it as an object, an attacker who can inject HTML can clobber the variable. Inject a form with id config containing an input named apiBase value //evil and document.config.apiBase reads as //evil.

HTMLCollection ambiguity

Two elements with the same id form a collection. document.config becomes a list, not a node. Some libraries handle this, most do not. Crash the path with a third element and you can change the type unpredictably.

Chaining to XSS

Libraries that evaluate window.callback as code execute the clobbered string. We have seen this on legacy admin panels, ad SDKs, and some analytics loaders. The injection vector is often a sanitized comment field that allows form, input, or iframe with id.

  • An anchor with id globalConfig and href javascript:alert(1) clobbers a config object with toString that yields the URL
  • A form with id window and input name location value //evil overwrites a reference to window.location
  • An iframe with name top src //evil clobbers top references in older code

Prototype pollution as accelerant

Many DOM Clobbering chains land in apps that also have prototype pollution. Clobber a property, then pollute Object.prototype to make the clobber survive deep clones. This is how researchers escalated several Gmail and bug bounty findings.

Sanitizer bypasses

DOMPurify before 2.0.17 allowed namespaced elements that survived as named references. Sanitize HTML by default strips id and name attributes but many app configurations keep them for accessibility. Audit your allowlist.

Discovery workflow

  1. Grep the front end bundle for document.x, window.x patterns with unquoted property reads
  2. List user controlled HTML sinks, comments, profile bio, markdown
  3. For each candidate, attempt to inject a form or iframe with matching id and name
  4. Verify in browser, then chain to a real sink like dynamic code execution or innerHTML

Remediation

  1. Strip id and name from user HTML or namespace them with a prefix
  2. Use const config defined at module scope, never read from document or window
  3. Adopt the Sanitizer API or a strict DOMPurify config
  4. Add Trusted Types policy that blocks string to HTML in dangerous sinks
40+
DOM Clobbering CVEs since 2021
$3.2k
Bounty average for confirmed clobbering XSS
Every named HTML element is a global variable waiting to be set by the wrong user.

Read more field notes, explore our services, or get in touch at info@bipi.in. Privacy Policy · Terms.