The vulnerability is a logic flaw in DOMPurify's IN_PLACE sanitization mode. It arises from a combination of incorrect assumptions between different internal functions when handling a detached DOM root element, specifically a <form> element.
The core of the issue lies in the interaction between three functions:
_forceRemove: This function is supposed to remove a node. However, if the node has no parent (is a detached root), it fails silently without removing the node or signaling an error.
_isClobbered: This function checks if an element's properties have been overwritten by descendant elements (a 'DOM Clobbering' attack).
_sanitizeAttributes: This function is responsible for cleaning element attributes. It calls _isClobbered and, if it returns true, _sanitizeAttributes immediately stops execution for that element, assuming _forceRemove has already dealt with it.
When an attacker provides a clobbered, detached <form> element to DOMPurify.sanitize with {IN_PLACE: true}:
_sanitizeElements calls _forceRemove on the root form.
_forceRemove does nothing because the form has no parent.
- The main loop continues and calls
_sanitizeAttributes on the same root form.
_sanitizeAttributes calls _isClobbered, which returns true.
_sanitizeAttributes then immediately returns, skipping all attribute sanitization for the root element.
As a result, any malicious attributes (like onmouseover, onclick, etc.) on the root <form> element are left intact, leading to a Cross-Site Scripting (XSS) vulnerability when the 'sanitized' element is inserted into the main document.
The fix, identified in commit 428b9b662933534d94573994343385b93de2b559, was to add a check at the beginning of the main DOMPurify.sanitize function. This check detects if it's running in IN_PLACE mode on a detached, clobbered element and, if so, throws an exception, preventing the vulnerable logic from ever being reached.