DOMPurify XSS via selectedcontent re-clone
Summary
DOMPurify 3.4.4 allowsselectedcontent by default, allowing a chain in which browsers "re-clone" an XSS payload after sanitization, effectively bypassing DOMPurify. Details
The chain is as follows:- The browser parses the input and creates a `
clone from the selected - DOMPurify walks and sanitizes that generated clone.
- DOMPurify reaches the original
and removesselected=javascript:1 - The browser refreshes the
clone from the originaloption's content. - The refreshed clone is in a subtree DOMPurify already walked, which DOMPurify doesn't go back to sanitize
- The returned string contains unsanitized markup inside
.
PoC
const dirty =
'' +
'' +
'x' +
'';const clean = DOMPurify.sanitize(dirty);
console.log(clean);
document.body.innerHTML = clean;
Observed "sanitized" output in Chromium 148/WebKit 625:
xxAfter reinsertion, the browser updates the live DOM and strips the handler from the displayed clone, but the onerror has already fired:
xx
Reproduced in Chromium and WebKit, but not Safari (not yet latest WebKit) or Firefox. Will likely change with browser support for selectedcontent`.
Impact
This is a default-configuration DOMPurify sanitizer bypass resulting in XSS.Applications 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.