GHSA-x4vx-rjvf-j5p4: DOMPurify: `IN_PLACE` mode trusts attacker-controlled `nodeName` on live non-form nodes, allowing script retention and XSS via attacker-supplied DOM objects
Summary
When DOMPurify.sanitize(root, { IN_PLACE: true }) is called on an attacker-supplied live DOM node, DOMPurify still trusts currentNode.nodeName for non-form nodes in the main _sanitizeElements pipeline. A real <script> child node whose observable nodeName is attacker-controlled can therefore be misclassified as an allowed element and retained. When the sanitized tree is inserted into a live document, the script executes.
This affects current 3.4.6. The recent IN_PLACE hardening work covers clobbered form handling and foreign-realm shadow/template traversal, but does not harden the main per-node element decision for hostile non-form live nodes.
Affected
- DOMPurify 3.4.6
- Any caller that does DOMPurify.sanitize(node, { IN_PLACE: true }) on attacker-supplied live DOM nodes
- Verified attacker-controlled node sources:
- same-origin iframe → live node passed by reference
- same-origin window.open() popup → live node passed by reference
- same-origin foreign node adopted into the host document via document.adoptNode(node) and then sanitized in-place
Not affected:
- String-input DOMPurify.sanitize(dirtyString)
Vulnerability details
Code paths
[A] — _sanitizeElements uses the instance-visible nodeName for the allow/forbid decision:
const _sanitizeElements = function (currentNode: any): boolean {
...
if (_isClobbered(currentNode)) {
_forceRemove(currentNode);
return true;
}
const tagName = transformCaseFunc(currentNode.nodeName);
...
if (
FORBID_TAGS[tagName] ||
(!(...) && !ALLOWED_TAGS[tagName])
) {
...
_forceRemove(currentNode);
return true;
}
...
};
For non-form nodes, _isClobbered(currentNode) returns false early. The subsequent element decision therefore trusts currentNode.nodeName directly.
[B] — _isClobbered is form-specific:
const _isClobbered = function (element: Element): boolean {
const realTagName = getNodeName ? getNodeName(element) : null;
if (typeof realTagName !== 'string') {
return false;
}
if (transformCaseFunc(realTagName) !== 'form
Details
Original advisory: https://github.com/advisories/GHSA-x4vx-rjvf-j5p4
Exploitation outlook
EPSS (FIRST.org) estimates each CVE’s probability of exploitation in the next 30 days — here is the CSIRTS.com read on those numbers.
- Low exploitation riskCVE-2026-659010.17% 30-day exploitation probability — currently an unlikely target, but scores change as exploit code circulates. Riskier than 6% of all scored CVEs.
Referenced CVEs
| CVE | CSIRTS overview | External |
|---|---|---|
| CVE-2026-65901 | coverage & exploitation status | NVD · CVE.org |
Same CVEs, other sources
How other CERTs, PSIRTs and databases cover the vulnerabilities in this advisory.
More from GitHub Security Advisories
- mediumGHSA-xm43-3m56-w3wf: Ghost: Paid gift memberships obtainable at minimal cost via the donations feature2026-08-04
- mediumGHSA-chgm-3698-jm42: Ghost: Member existence leak via magic link sign-in response2026-08-04
- highGHSA-xpp7-93x6-v29m: XSS in Ghost's ActivityPub client2026-08-04
- mediumGHSA-7mpp-r37j-x5wh: Ghost: Session Fixation in Ghost Admin2026-08-04
- mediumGHSA-cjc9-q5gf-327p: Ghost: Theme Upload Path Traversal2026-08-04