[The page](https://portswigger.net/web-security/dom-based/dom-clobbering/lab-dom-xss-exploiting-dom-clobbering) uses a risky fallback pattern. ### What’s happening This page renders comments client-side: ```html <script src="/resources/js/domPurify-2.0.15.js"></script> <script src="/resources/js/loadCommentsWithDomClobbering.js"></script> <script>loadComments('/post/comment')</script> ``` `loadCommentsWithDomClobbering.js` sanitizes comment HTML with DOMPurify, injects it into the DOM, and uses a dangerous pattern like: ```js let defaultAvatar = window.defaultAvatar || { avatar: '/resources/images/avatarDefault.svg' } ``` Because browsers can expose elements with `id="defaultAvatar"` as `window.defaultAvatar`, attacker HTML can **clobber** that global and control what `defaultAvatar` becomes. --- ## Steps to solve ### 1) Post the clobbering payload (first comment) On any blog post, submit a comment with: ```html <a id=defaultAvatar><a id=defaultAvatar name=avatar href="cid:&quot;onerror=alert(1)//"> ``` **Why it works (tight):** * Two elements with the same `id=defaultAvatar` → Chrome exposes `window.defaultAvatar` as a **DOM collection**. * `name=avatar` on the second anchor → creates `window.defaultAvatar.avatar`. * That `.avatar` resolves to the anchor element, and when later used as a string, Chrome effectively uses its **href**. * DOMPurify allows `cid:` and keeps `&quot;`, which becomes a real `"` at runtime: * `cid:&quot;onerror=alert(1)//` → `cid:"onerror=alert(1)//` So the app ends up consuming an “avatar URL” that contains an injected quote. --- ### 2) Trigger a re-render (second comment) Add a **second** comment with any text (e.g., `test`). This forces the comment rendering code to run again **after** the global is already clobbered. --- ### 3) Observe XSS On the next render/load cycle, when the app uses the clobbered `defaultAvatar.avatar` to build an image element (e.g., `img src="...")`, the injected `"` breaks out of the `src` attribute and injects: `onerror=alert(1)//` → `alert(1)` fires. --- ## Key takeaway The root bug isn’t “DOMPurify failed.” It’s that the app treats `window.defaultAvatar` as trusted configuration (`window.defaultAvatar || {...}`), so user-controlled DOM can override it (DOM clobbering).