DOMPurify: IN_PLACE mode preserves attributes of a clobbered root element, allowing XSS via attacker-controlled root DOM
Description
DOMPurify IN_PLACE mode with a `` root and a clobber-named child bypasses attribute sanitization, leaving event handlers active.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
DOMPurify IN_PLACE mode with a `` root and a clobber-named child bypasses attribute sanitization, leaving event handlers active.
Vulnerability
In DOMPurify versions ≤3.4.5 (including commit 89da34e), when DOMPurify.sanitize(root, { IN_PLACE: true }) is called and root is an HTMLFormElement, a single descendant element with a name= attribute matching nodeName, setAttribute, namespaceURI, insertBefore, hasChildNodes, or childNodes can bypass attribute sanitization on the root. The _forceRemove call on the clobbered child silently no-ops because the root has no parent; the iterator then reaches _sanitizeAttributes, which early-returns on clobbered nodes, leaving event handler attributes (e.g., onmouseover, onclick) on the root untouched [1][2].
Exploitation
An attacker must control the HTML that is parsed to become the root node (e.g., via createElement('template').innerHTML and taking template.content.firstElementChild) and must ensure a child element with one of the specified name= values is present inside that root. The root must be an HTMLFormElement carrying event handlers. The user must trigger the IN_PLACE code path explicitly. No additional authentication is required beyond the ability to supply the untrusted markup [1][2].
Impact
Successful exploitation results in stored or reflected cross-site scripting (XSS) against the user who views the sanitized output. The attacker gains the ability to execute arbitrary JavaScript in the context of the user's session, potentially leading to session theft, credential harvesting, or further site compromise. The CVSS v3.1 score is 6.1 (Medium) [2].
Mitigation
As of June 2026, no official patch has been released for CVE-2026-49459. Users are advised to either avoid using IN_PLACE: true with untrusted node inputs, or ensure the root is never an HTMLFormElement (e.g., by wrapping it in a ` before sanitization). The string-based DOMPurify.sanitize(dirtyString)` path is not affected [1][2].
AI Insight generated on Jun 15, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2Patches
1bb7739e5bccerelease: 3.4.6 (#1394)
25 files changed · +1676 −152
dist/purify.cjs.d.ts+1 −1 modified@@ -1,4 +1,4 @@ -/*! @license DOMPurify 3.4.5 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.5/LICENSE */ +/*! @license DOMPurify 3.4.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.6/LICENSE */ import { TrustedTypePolicy, TrustedTypesWindow, TrustedHTML } from 'trusted-types/lib/index.js';
dist/purify.cjs.js+179 −26 modified@@ -1,4 +1,4 @@ -/*! @license DOMPurify 3.4.5 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.5/LICENSE */ +/*! @license DOMPurify 3.4.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.6/LICENSE */ 'use strict'; @@ -334,11 +334,20 @@ const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i); // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType const NODE_TYPE = { element: 1, + attribute: 2, text: 3, + cdataSection: 4, + entityReference: 5, + // Deprecated + entityNode: 6, // Deprecated progressingInstruction: 7, comment: 8, - document: 9}; + document: 9, + documentType: 10, + documentFragment: 11, + notation: 12 // Deprecated +}; const getGlobal = function getGlobal() { return typeof window === 'undefined' ? null : window; }; @@ -396,7 +405,7 @@ const _createHooksMap = function _createHooksMap() { function createDOMPurify() { let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal(); const DOMPurify = root => createDOMPurify(root); - DOMPurify.version = '3.4.5'; + DOMPurify.version = '3.4.6'; DOMPurify.removed = []; if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) { // Not running in a browser, provide a factory function @@ -407,23 +416,26 @@ function createDOMPurify() { let document = window.document; const originalDocument = document; const currentScript = originalDocument.currentScript; - const DocumentFragment = window.DocumentFragment, - HTMLTemplateElement = window.HTMLTemplateElement, + window.DocumentFragment; + const HTMLTemplateElement = window.HTMLTemplateElement, Node = window.Node, Element = window.Element, NodeFilter = window.NodeFilter, - _window$NamedNodeMap = window.NamedNodeMap, - NamedNodeMap = _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap, - HTMLFormElement = window.HTMLFormElement, - DOMParser = window.DOMParser, + _window$NamedNodeMap = window.NamedNodeMap; + _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap; + window.HTMLFormElement; + const DOMParser = window.DOMParser, trustedTypes = window.trustedTypes; const ElementPrototype = Element.prototype; const cloneNode = lookupGetter(ElementPrototype, 'cloneNode'); const remove = lookupGetter(ElementPrototype, 'remove'); const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling'); const getChildNodes = lookupGetter(ElementPrototype, 'childNodes'); const getParentNode = lookupGetter(ElementPrototype, 'parentNode'); + const getShadowRoot = lookupGetter(ElementPrototype, 'shadowRoot'); + const getAttributes = lookupGetter(ElementPrototype, 'attributes'); const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeType') : null; + const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeName') : null; // As per issue #47, the web-components registry is inherited by a // new document created via createHTMLDocument. As per the spec // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries) @@ -1014,11 +1026,100 @@ function createDOMPurify() { /** * _isClobbered * + * Detect DOM-clobbering on HTMLFormElement nodes. Form is the only HTML + * interface with [LegacyOverrideBuiltIns]; a descendant element with a + * `name` attribute matching a prototype property shadows that property + * on direct reads. We use this check at the IN_PLACE entry-point and + * during attribute sanitization to refuse clobbered forms. + * + * Realm safety (GHSA-hpcv-96wg-7vj8): every check in this function must + * work for foreign-realm forms — e.g. a <form> created inside a same- + * origin iframe and then handed to a parent-realm DOMPurify instance + * with IN_PLACE: true. The original implementation used + * `element instanceof HTMLFormElement` and `element.attributes + * instanceof NamedNodeMap`, both of which are realm-bound: a foreign- + * realm form is an instance of the *foreign* realm's HTMLFormElement, + * not the parent realm's. The instanceof short-circuited to false and + * the function returned false (= not clobbered) regardless of how + * thoroughly the form was clobbered. Sanitize then walked a clobbered + * .attributes and missed every attribute on the form root, leaving + * onmouseover / onclick / formaction / etc. intact. + * + * The realm-independent replacements: + * - HTMLFormElement detection — read the tag name through the cached + * Node.prototype.nodeName getter. WebIDL getters operate on internal + * slots that exist on every real Node regardless of which realm + * minted the JS wrapper, so getNodeName(foreignForm) === "FORM". + * - NamedNodeMap detection — compare the direct .attributes read + * against the cached Element.prototype.attributes getter. Same + * equality-probe pattern we use for .childNodes: if a clobbering + * child shadows the named property, the two reads diverge; if not, + * both return the same NamedNodeMap (same-realm OR foreign-realm — + * doesn't matter, both are the canonical attributes object for the + * node). + * * @param element element to check for clobbering attacks * @return true if clobbered, false if safe */ const _isClobbered = function _isClobbered(element) { - return element instanceof HTMLFormElement && (typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' || !(element.attributes instanceof NamedNodeMap) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function'); + // Realm-independent tag-name probe. If we can't determine the tag + // name at all, we can't reason about clobbering — return false + // (the caller's other defences still apply). + const realTagName = getNodeName ? getNodeName(element) : null; + if (typeof realTagName !== 'string') { + return false; + } + if (transformCaseFunc(realTagName) !== 'form') { + return false; + } + return typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' || + // Realm-safe NamedNodeMap detection: equality against the cached + // prototype getter. Clobbered .attributes (e.g. <input name="attributes">) + // makes the direct read diverge from the cached read; a clean form + // (same-realm OR foreign-realm) has both reads pointing at the same + // canonical NamedNodeMap. + element.attributes !== getAttributes(element) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function' || + // HTMLFormElement has [LegacyOverrideBuiltIns]: a descendant named + // "childNodes" shadows the prototype getter. Direct reads of + // form.childNodes from a clobbered form return the named child + // instead of the real NodeList, so any walk that reads it directly + // skips the form's real children. Compare the direct read to the + // cached Node.prototype getter — when the form's named-property + // getter intercepts the read, the two values differ and we flag + // the form. This catches every clobbering child type (input, + // select, etc.) regardless of whether the named child happens to + // carry a numeric .length, which a typeof-based probe would miss + // (e.g. HTMLSelectElement.length is a defined unsigned-long). + element.childNodes !== getChildNodes(element); + }; + /** + * Checks whether the given value is a DocumentFragment from any realm. + * + * Realm safety (GHSA-hpcv-96wg-7vj8): the original sites used + * `value instanceof DocumentFragment`, which is realm-bound — a fragment + * from a foreign realm (template content or shadow root from an iframe + * document) is an instance of the foreign realm's DocumentFragment, not + * the parent realm's, so the check returned false and the template- + * content / shadow-root recursion was silently skipped. The attacker + * payload inside survived untouched. + * + * The realm-independent replacement reads `nodeType` through the cached + * Node.prototype getter and compares to the DOCUMENT_FRAGMENT_NODE + * constant (11). nodeType is a numeric value resolved from the node's + * internal slot, identical across realms for the same kind of node. + * + * @param value object to check + * @return true if value is a DocumentFragment-shaped node from any realm + */ + const _isDocumentFragment = function _isDocumentFragment(value) { + if (!getNodeType || typeof value !== 'object' || value === null) { + return false; + } + try { + return getNodeType(value) === NODE_TYPE.documentFragment; + } catch (_) { + return false; + } }; /** * Checks whether the given object is a DOM node, including nodes that @@ -1123,8 +1224,14 @@ function createDOMPurify() { _forceRemove(currentNode); return true; } - /* Check whether element has a valid namespace */ - if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) { + /* Check whether element has a valid namespace. + Realm-safe check (GHSA-hpcv-96wg-7vj8): use the cached Node.prototype + nodeType getter rather than `instanceof Element`, which is realm- + bound and short-circuits to false for any node minted in a different + realm — letting a foreign-realm element with a forbidden namespace + slip past the namespace check entirely. */ + const nt = getNodeType ? getNodeType(currentNode) : currentNode.nodeType; + if (nt === NODE_TYPE.element && !_checkValidNamespace(currentNode)) { _forceRemove(currentNode); return true; } @@ -1351,8 +1458,11 @@ function createDOMPurify() { _sanitizeElements(shadowNode); /* Check attributes next */ _sanitizeAttributes(shadowNode); - /* Deep shadow DOM detected */ - if (shadowNode.content instanceof DocumentFragment) { + /* Deep shadow DOM detected. + Realm-safe check (GHSA-hpcv-96wg-7vj8): use nodeType against the + DOCUMENT_FRAGMENT_NODE constant rather than instanceof, so we + recurse into <template>.content from foreign realms too. */ + if (_isDocumentFragment(shadowNode.content)) { _sanitizeShadowDOM2(shadowNode.content); } } @@ -1376,21 +1486,42 @@ function createDOMPurify() { * existing _sanitizeShadowDOM template-content recursion) stay * untouched — string-input paths are not affected. * + * DOM-Clobbering hardening: HTMLFormElement carries the WebIDL + * [LegacyOverrideBuiltIns] extended attribute, so a descendant element + * named `nodeType`, `shadowRoot`, or `childNodes` shadows the matching + * prototype getter on the form. Reading those properties directly off + * the node would let an attacker steer this walk past shadow hosts + * (e.g. <input name="childNodes"> collapses the form's child list to + * the input itself, so descent stops dead and any shadow root deeper + * in the subtree is never sanitized). Every property access here is + * therefore routed through the cached prototype getter; the form's + * named-property getter cannot intercept those reads. + * * @param root the subtree root to walk for attached shadow roots */ const _sanitizeAttachedShadowRoots2 = function _sanitizeAttachedShadowRoots(root) { - if (root.nodeType === NODE_TYPE.element && root.shadowRoot instanceof DocumentFragment) { - const sr = root.shadowRoot; - // Recurse first so that nested shadow roots are reached even if - // _sanitizeShadowDOM removes hosts at this level. - _sanitizeAttachedShadowRoots2(sr); - _sanitizeShadowDOM2(sr); + const nodeType = getNodeType ? getNodeType(root) : root.nodeType; + if (nodeType === NODE_TYPE.element) { + const sr = getShadowRoot ? getShadowRoot(root) : root.shadowRoot; + // Realm-safe check (GHSA-hpcv-96wg-7vj8): use nodeType-based + // detection rather than `instanceof DocumentFragment`, which is + // realm-bound and silently skipped shadow roots whose host element + // belonged to a foreign realm (e.g. iframe.contentDocument + // attachShadow). A foreign-realm ShadowRoot extends the foreign + // realm's DocumentFragment, not ours, so the old instanceof check + // returned false and the shadow subtree was never walked. + if (_isDocumentFragment(sr)) { + // Recurse first so that nested shadow roots are reached even if + // _sanitizeShadowDOM removes hosts at this level. + _sanitizeAttachedShadowRoots2(sr); + _sanitizeShadowDOM2(sr); + } } // Snapshot children before recursing. Sanitization of one subtree // (e.g. via an uponSanitizeShadowNode hook) may detach siblings, // and naive nextSibling traversal would silently skip the rest of // the list once a node is detached. - const childNodes = root.childNodes; + const childNodes = getChildNodes ? getChildNodes(root) : root.childNodes; if (!childNodes) { return; } @@ -1438,14 +1569,31 @@ function createDOMPurify() { IN_PLACE = false; } if (IN_PLACE) { - /* Do some early pre-sanitization to avoid unsafe root nodes */ - const nn = dirty.nodeName; + /* Do some early pre-sanitization to avoid unsafe root nodes. + Read nodeName through the cached prototype getter — a clobbering + child named "nodeName" on the form root would otherwise shadow + the property and let this check skip the root-allowlist + validation entirely. */ + const nn = getNodeName ? getNodeName(dirty) : dirty.nodeName; if (typeof nn === 'string') { const tagName = transformCaseFunc(nn); if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) { throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place'); } } + /* Pre-flight the root through _isClobbered. The iterator-driven + removal path can not detach a parent-less root: _forceRemove + falls through to Element.prototype.remove(), which per spec + is a no-op on a node with no parent. A clobbered root would + then survive the main loop with its attributes uninspected, + because _sanitizeAttributes early-returns on _isClobbered. The + result would be an attacker-controlled form, complete with any + event-handler attributes the caller passed in, handed back to + the application unsanitized. Refuse to sanitize such a root + the same way we refuse a forbidden tag. GHSA-r47g-fvhr-h676. */ + if (_isClobbered(dirty)) { + throw typeErrorCreate('root node is clobbered and cannot be sanitized in-place'); + } /* Sanitize attached shadow roots before the main iterator runs. The iterator does not descend into shadow trees. */ _sanitizeAttachedShadowRoots2(dirty); @@ -1465,7 +1613,9 @@ function createDOMPurify() { } /* Clonable shadow roots are deep-cloned by importNode(); sanitize them before the main iterator runs, since the iterator does not - descend into shadow trees. */ + descend into shadow trees. The walk routes every read through a + cached prototype getter so clobbering descendants on a form root + cannot hide a shadow host from this pass. */ _sanitizeAttachedShadowRoots2(importedNode); } else { /* Exit directly if we have nothing to do */ @@ -1493,8 +1643,11 @@ function createDOMPurify() { _sanitizeElements(currentNode); /* Check attributes next */ _sanitizeAttributes(currentNode); - /* Shadow DOM detected, sanitize it */ - if (currentNode.content instanceof DocumentFragment) { + /* Shadow DOM detected, sanitize it. + Realm-safe check (GHSA-hpcv-96wg-7vj8): nodeType-based detection + instead of instanceof, so foreign-realm <template>.content is + walked correctly. */ + if (_isDocumentFragment(currentNode.content)) { _sanitizeShadowDOM2(currentNode.content); } }
dist/purify.cjs.js.map+1 −1 modifieddist/purify.es.d.mts+1 −1 modified@@ -1,4 +1,4 @@ -/*! @license DOMPurify 3.4.5 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.5/LICENSE */ +/*! @license DOMPurify 3.4.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.6/LICENSE */ import { TrustedTypePolicy, TrustedTypesWindow, TrustedHTML } from 'trusted-types/lib/index.js';
dist/purify.es.mjs+179 −26 modified@@ -1,4 +1,4 @@ -/*! @license DOMPurify 3.4.5 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.5/LICENSE */ +/*! @license DOMPurify 3.4.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.6/LICENSE */ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); @@ -332,11 +332,20 @@ const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i); // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType const NODE_TYPE = { element: 1, + attribute: 2, text: 3, + cdataSection: 4, + entityReference: 5, + // Deprecated + entityNode: 6, // Deprecated progressingInstruction: 7, comment: 8, - document: 9}; + document: 9, + documentType: 10, + documentFragment: 11, + notation: 12 // Deprecated +}; const getGlobal = function getGlobal() { return typeof window === 'undefined' ? null : window; }; @@ -394,7 +403,7 @@ const _createHooksMap = function _createHooksMap() { function createDOMPurify() { let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal(); const DOMPurify = root => createDOMPurify(root); - DOMPurify.version = '3.4.5'; + DOMPurify.version = '3.4.6'; DOMPurify.removed = []; if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) { // Not running in a browser, provide a factory function @@ -405,23 +414,26 @@ function createDOMPurify() { let document = window.document; const originalDocument = document; const currentScript = originalDocument.currentScript; - const DocumentFragment = window.DocumentFragment, - HTMLTemplateElement = window.HTMLTemplateElement, + window.DocumentFragment; + const HTMLTemplateElement = window.HTMLTemplateElement, Node = window.Node, Element = window.Element, NodeFilter = window.NodeFilter, - _window$NamedNodeMap = window.NamedNodeMap, - NamedNodeMap = _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap, - HTMLFormElement = window.HTMLFormElement, - DOMParser = window.DOMParser, + _window$NamedNodeMap = window.NamedNodeMap; + _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap; + window.HTMLFormElement; + const DOMParser = window.DOMParser, trustedTypes = window.trustedTypes; const ElementPrototype = Element.prototype; const cloneNode = lookupGetter(ElementPrototype, 'cloneNode'); const remove = lookupGetter(ElementPrototype, 'remove'); const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling'); const getChildNodes = lookupGetter(ElementPrototype, 'childNodes'); const getParentNode = lookupGetter(ElementPrototype, 'parentNode'); + const getShadowRoot = lookupGetter(ElementPrototype, 'shadowRoot'); + const getAttributes = lookupGetter(ElementPrototype, 'attributes'); const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeType') : null; + const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeName') : null; // As per issue #47, the web-components registry is inherited by a // new document created via createHTMLDocument. As per the spec // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries) @@ -1012,11 +1024,100 @@ function createDOMPurify() { /** * _isClobbered * + * Detect DOM-clobbering on HTMLFormElement nodes. Form is the only HTML + * interface with [LegacyOverrideBuiltIns]; a descendant element with a + * `name` attribute matching a prototype property shadows that property + * on direct reads. We use this check at the IN_PLACE entry-point and + * during attribute sanitization to refuse clobbered forms. + * + * Realm safety (GHSA-hpcv-96wg-7vj8): every check in this function must + * work for foreign-realm forms — e.g. a <form> created inside a same- + * origin iframe and then handed to a parent-realm DOMPurify instance + * with IN_PLACE: true. The original implementation used + * `element instanceof HTMLFormElement` and `element.attributes + * instanceof NamedNodeMap`, both of which are realm-bound: a foreign- + * realm form is an instance of the *foreign* realm's HTMLFormElement, + * not the parent realm's. The instanceof short-circuited to false and + * the function returned false (= not clobbered) regardless of how + * thoroughly the form was clobbered. Sanitize then walked a clobbered + * .attributes and missed every attribute on the form root, leaving + * onmouseover / onclick / formaction / etc. intact. + * + * The realm-independent replacements: + * - HTMLFormElement detection — read the tag name through the cached + * Node.prototype.nodeName getter. WebIDL getters operate on internal + * slots that exist on every real Node regardless of which realm + * minted the JS wrapper, so getNodeName(foreignForm) === "FORM". + * - NamedNodeMap detection — compare the direct .attributes read + * against the cached Element.prototype.attributes getter. Same + * equality-probe pattern we use for .childNodes: if a clobbering + * child shadows the named property, the two reads diverge; if not, + * both return the same NamedNodeMap (same-realm OR foreign-realm — + * doesn't matter, both are the canonical attributes object for the + * node). + * * @param element element to check for clobbering attacks * @return true if clobbered, false if safe */ const _isClobbered = function _isClobbered(element) { - return element instanceof HTMLFormElement && (typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' || !(element.attributes instanceof NamedNodeMap) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function'); + // Realm-independent tag-name probe. If we can't determine the tag + // name at all, we can't reason about clobbering — return false + // (the caller's other defences still apply). + const realTagName = getNodeName ? getNodeName(element) : null; + if (typeof realTagName !== 'string') { + return false; + } + if (transformCaseFunc(realTagName) !== 'form') { + return false; + } + return typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' || + // Realm-safe NamedNodeMap detection: equality against the cached + // prototype getter. Clobbered .attributes (e.g. <input name="attributes">) + // makes the direct read diverge from the cached read; a clean form + // (same-realm OR foreign-realm) has both reads pointing at the same + // canonical NamedNodeMap. + element.attributes !== getAttributes(element) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function' || + // HTMLFormElement has [LegacyOverrideBuiltIns]: a descendant named + // "childNodes" shadows the prototype getter. Direct reads of + // form.childNodes from a clobbered form return the named child + // instead of the real NodeList, so any walk that reads it directly + // skips the form's real children. Compare the direct read to the + // cached Node.prototype getter — when the form's named-property + // getter intercepts the read, the two values differ and we flag + // the form. This catches every clobbering child type (input, + // select, etc.) regardless of whether the named child happens to + // carry a numeric .length, which a typeof-based probe would miss + // (e.g. HTMLSelectElement.length is a defined unsigned-long). + element.childNodes !== getChildNodes(element); + }; + /** + * Checks whether the given value is a DocumentFragment from any realm. + * + * Realm safety (GHSA-hpcv-96wg-7vj8): the original sites used + * `value instanceof DocumentFragment`, which is realm-bound — a fragment + * from a foreign realm (template content or shadow root from an iframe + * document) is an instance of the foreign realm's DocumentFragment, not + * the parent realm's, so the check returned false and the template- + * content / shadow-root recursion was silently skipped. The attacker + * payload inside survived untouched. + * + * The realm-independent replacement reads `nodeType` through the cached + * Node.prototype getter and compares to the DOCUMENT_FRAGMENT_NODE + * constant (11). nodeType is a numeric value resolved from the node's + * internal slot, identical across realms for the same kind of node. + * + * @param value object to check + * @return true if value is a DocumentFragment-shaped node from any realm + */ + const _isDocumentFragment = function _isDocumentFragment(value) { + if (!getNodeType || typeof value !== 'object' || value === null) { + return false; + } + try { + return getNodeType(value) === NODE_TYPE.documentFragment; + } catch (_) { + return false; + } }; /** * Checks whether the given object is a DOM node, including nodes that @@ -1121,8 +1222,14 @@ function createDOMPurify() { _forceRemove(currentNode); return true; } - /* Check whether element has a valid namespace */ - if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) { + /* Check whether element has a valid namespace. + Realm-safe check (GHSA-hpcv-96wg-7vj8): use the cached Node.prototype + nodeType getter rather than `instanceof Element`, which is realm- + bound and short-circuits to false for any node minted in a different + realm — letting a foreign-realm element with a forbidden namespace + slip past the namespace check entirely. */ + const nt = getNodeType ? getNodeType(currentNode) : currentNode.nodeType; + if (nt === NODE_TYPE.element && !_checkValidNamespace(currentNode)) { _forceRemove(currentNode); return true; } @@ -1349,8 +1456,11 @@ function createDOMPurify() { _sanitizeElements(shadowNode); /* Check attributes next */ _sanitizeAttributes(shadowNode); - /* Deep shadow DOM detected */ - if (shadowNode.content instanceof DocumentFragment) { + /* Deep shadow DOM detected. + Realm-safe check (GHSA-hpcv-96wg-7vj8): use nodeType against the + DOCUMENT_FRAGMENT_NODE constant rather than instanceof, so we + recurse into <template>.content from foreign realms too. */ + if (_isDocumentFragment(shadowNode.content)) { _sanitizeShadowDOM2(shadowNode.content); } } @@ -1374,21 +1484,42 @@ function createDOMPurify() { * existing _sanitizeShadowDOM template-content recursion) stay * untouched — string-input paths are not affected. * + * DOM-Clobbering hardening: HTMLFormElement carries the WebIDL + * [LegacyOverrideBuiltIns] extended attribute, so a descendant element + * named `nodeType`, `shadowRoot`, or `childNodes` shadows the matching + * prototype getter on the form. Reading those properties directly off + * the node would let an attacker steer this walk past shadow hosts + * (e.g. <input name="childNodes"> collapses the form's child list to + * the input itself, so descent stops dead and any shadow root deeper + * in the subtree is never sanitized). Every property access here is + * therefore routed through the cached prototype getter; the form's + * named-property getter cannot intercept those reads. + * * @param root the subtree root to walk for attached shadow roots */ const _sanitizeAttachedShadowRoots2 = function _sanitizeAttachedShadowRoots(root) { - if (root.nodeType === NODE_TYPE.element && root.shadowRoot instanceof DocumentFragment) { - const sr = root.shadowRoot; - // Recurse first so that nested shadow roots are reached even if - // _sanitizeShadowDOM removes hosts at this level. - _sanitizeAttachedShadowRoots2(sr); - _sanitizeShadowDOM2(sr); + const nodeType = getNodeType ? getNodeType(root) : root.nodeType; + if (nodeType === NODE_TYPE.element) { + const sr = getShadowRoot ? getShadowRoot(root) : root.shadowRoot; + // Realm-safe check (GHSA-hpcv-96wg-7vj8): use nodeType-based + // detection rather than `instanceof DocumentFragment`, which is + // realm-bound and silently skipped shadow roots whose host element + // belonged to a foreign realm (e.g. iframe.contentDocument + // attachShadow). A foreign-realm ShadowRoot extends the foreign + // realm's DocumentFragment, not ours, so the old instanceof check + // returned false and the shadow subtree was never walked. + if (_isDocumentFragment(sr)) { + // Recurse first so that nested shadow roots are reached even if + // _sanitizeShadowDOM removes hosts at this level. + _sanitizeAttachedShadowRoots2(sr); + _sanitizeShadowDOM2(sr); + } } // Snapshot children before recursing. Sanitization of one subtree // (e.g. via an uponSanitizeShadowNode hook) may detach siblings, // and naive nextSibling traversal would silently skip the rest of // the list once a node is detached. - const childNodes = root.childNodes; + const childNodes = getChildNodes ? getChildNodes(root) : root.childNodes; if (!childNodes) { return; } @@ -1436,14 +1567,31 @@ function createDOMPurify() { IN_PLACE = false; } if (IN_PLACE) { - /* Do some early pre-sanitization to avoid unsafe root nodes */ - const nn = dirty.nodeName; + /* Do some early pre-sanitization to avoid unsafe root nodes. + Read nodeName through the cached prototype getter — a clobbering + child named "nodeName" on the form root would otherwise shadow + the property and let this check skip the root-allowlist + validation entirely. */ + const nn = getNodeName ? getNodeName(dirty) : dirty.nodeName; if (typeof nn === 'string') { const tagName = transformCaseFunc(nn); if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) { throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place'); } } + /* Pre-flight the root through _isClobbered. The iterator-driven + removal path can not detach a parent-less root: _forceRemove + falls through to Element.prototype.remove(), which per spec + is a no-op on a node with no parent. A clobbered root would + then survive the main loop with its attributes uninspected, + because _sanitizeAttributes early-returns on _isClobbered. The + result would be an attacker-controlled form, complete with any + event-handler attributes the caller passed in, handed back to + the application unsanitized. Refuse to sanitize such a root + the same way we refuse a forbidden tag. GHSA-r47g-fvhr-h676. */ + if (_isClobbered(dirty)) { + throw typeErrorCreate('root node is clobbered and cannot be sanitized in-place'); + } /* Sanitize attached shadow roots before the main iterator runs. The iterator does not descend into shadow trees. */ _sanitizeAttachedShadowRoots2(dirty); @@ -1463,7 +1611,9 @@ function createDOMPurify() { } /* Clonable shadow roots are deep-cloned by importNode(); sanitize them before the main iterator runs, since the iterator does not - descend into shadow trees. */ + descend into shadow trees. The walk routes every read through a + cached prototype getter so clobbering descendants on a form root + cannot hide a shadow host from this pass. */ _sanitizeAttachedShadowRoots2(importedNode); } else { /* Exit directly if we have nothing to do */ @@ -1491,8 +1641,11 @@ function createDOMPurify() { _sanitizeElements(currentNode); /* Check attributes next */ _sanitizeAttributes(currentNode); - /* Shadow DOM detected, sanitize it */ - if (currentNode.content instanceof DocumentFragment) { + /* Shadow DOM detected, sanitize it. + Realm-safe check (GHSA-hpcv-96wg-7vj8): nodeType-based detection + instead of instanceof, so foreign-realm <template>.content is + walked correctly. */ + if (_isDocumentFragment(currentNode.content)) { _sanitizeShadowDOM2(currentNode.content); } }
dist/purify.es.mjs.map+1 −1 modifieddist/purify.js+179 −26 modified@@ -1,4 +1,4 @@ -/*! @license DOMPurify 3.4.5 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.5/LICENSE */ +/*! @license DOMPurify 3.4.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.6/LICENSE */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : @@ -338,11 +338,20 @@ // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType const NODE_TYPE = { element: 1, + attribute: 2, text: 3, + cdataSection: 4, + entityReference: 5, + // Deprecated + entityNode: 6, // Deprecated progressingInstruction: 7, comment: 8, - document: 9}; + document: 9, + documentType: 10, + documentFragment: 11, + notation: 12 // Deprecated + }; const getGlobal = function getGlobal() { return typeof window === 'undefined' ? null : window; }; @@ -400,7 +409,7 @@ function createDOMPurify() { let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal(); const DOMPurify = root => createDOMPurify(root); - DOMPurify.version = '3.4.5'; + DOMPurify.version = '3.4.6'; DOMPurify.removed = []; if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) { // Not running in a browser, provide a factory function @@ -411,23 +420,26 @@ let document = window.document; const originalDocument = document; const currentScript = originalDocument.currentScript; - const DocumentFragment = window.DocumentFragment, - HTMLTemplateElement = window.HTMLTemplateElement, + window.DocumentFragment; + const HTMLTemplateElement = window.HTMLTemplateElement, Node = window.Node, Element = window.Element, NodeFilter = window.NodeFilter, - _window$NamedNodeMap = window.NamedNodeMap, - NamedNodeMap = _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap, - HTMLFormElement = window.HTMLFormElement, - DOMParser = window.DOMParser, + _window$NamedNodeMap = window.NamedNodeMap; + _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap; + window.HTMLFormElement; + const DOMParser = window.DOMParser, trustedTypes = window.trustedTypes; const ElementPrototype = Element.prototype; const cloneNode = lookupGetter(ElementPrototype, 'cloneNode'); const remove = lookupGetter(ElementPrototype, 'remove'); const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling'); const getChildNodes = lookupGetter(ElementPrototype, 'childNodes'); const getParentNode = lookupGetter(ElementPrototype, 'parentNode'); + const getShadowRoot = lookupGetter(ElementPrototype, 'shadowRoot'); + const getAttributes = lookupGetter(ElementPrototype, 'attributes'); const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeType') : null; + const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeName') : null; // As per issue #47, the web-components registry is inherited by a // new document created via createHTMLDocument. As per the spec // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries) @@ -1018,11 +1030,100 @@ /** * _isClobbered * + * Detect DOM-clobbering on HTMLFormElement nodes. Form is the only HTML + * interface with [LegacyOverrideBuiltIns]; a descendant element with a + * `name` attribute matching a prototype property shadows that property + * on direct reads. We use this check at the IN_PLACE entry-point and + * during attribute sanitization to refuse clobbered forms. + * + * Realm safety (GHSA-hpcv-96wg-7vj8): every check in this function must + * work for foreign-realm forms — e.g. a <form> created inside a same- + * origin iframe and then handed to a parent-realm DOMPurify instance + * with IN_PLACE: true. The original implementation used + * `element instanceof HTMLFormElement` and `element.attributes + * instanceof NamedNodeMap`, both of which are realm-bound: a foreign- + * realm form is an instance of the *foreign* realm's HTMLFormElement, + * not the parent realm's. The instanceof short-circuited to false and + * the function returned false (= not clobbered) regardless of how + * thoroughly the form was clobbered. Sanitize then walked a clobbered + * .attributes and missed every attribute on the form root, leaving + * onmouseover / onclick / formaction / etc. intact. + * + * The realm-independent replacements: + * - HTMLFormElement detection — read the tag name through the cached + * Node.prototype.nodeName getter. WebIDL getters operate on internal + * slots that exist on every real Node regardless of which realm + * minted the JS wrapper, so getNodeName(foreignForm) === "FORM". + * - NamedNodeMap detection — compare the direct .attributes read + * against the cached Element.prototype.attributes getter. Same + * equality-probe pattern we use for .childNodes: if a clobbering + * child shadows the named property, the two reads diverge; if not, + * both return the same NamedNodeMap (same-realm OR foreign-realm — + * doesn't matter, both are the canonical attributes object for the + * node). + * * @param element element to check for clobbering attacks * @return true if clobbered, false if safe */ const _isClobbered = function _isClobbered(element) { - return element instanceof HTMLFormElement && (typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' || !(element.attributes instanceof NamedNodeMap) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function'); + // Realm-independent tag-name probe. If we can't determine the tag + // name at all, we can't reason about clobbering — return false + // (the caller's other defences still apply). + const realTagName = getNodeName ? getNodeName(element) : null; + if (typeof realTagName !== 'string') { + return false; + } + if (transformCaseFunc(realTagName) !== 'form') { + return false; + } + return typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' || + // Realm-safe NamedNodeMap detection: equality against the cached + // prototype getter. Clobbered .attributes (e.g. <input name="attributes">) + // makes the direct read diverge from the cached read; a clean form + // (same-realm OR foreign-realm) has both reads pointing at the same + // canonical NamedNodeMap. + element.attributes !== getAttributes(element) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function' || + // HTMLFormElement has [LegacyOverrideBuiltIns]: a descendant named + // "childNodes" shadows the prototype getter. Direct reads of + // form.childNodes from a clobbered form return the named child + // instead of the real NodeList, so any walk that reads it directly + // skips the form's real children. Compare the direct read to the + // cached Node.prototype getter — when the form's named-property + // getter intercepts the read, the two values differ and we flag + // the form. This catches every clobbering child type (input, + // select, etc.) regardless of whether the named child happens to + // carry a numeric .length, which a typeof-based probe would miss + // (e.g. HTMLSelectElement.length is a defined unsigned-long). + element.childNodes !== getChildNodes(element); + }; + /** + * Checks whether the given value is a DocumentFragment from any realm. + * + * Realm safety (GHSA-hpcv-96wg-7vj8): the original sites used + * `value instanceof DocumentFragment`, which is realm-bound — a fragment + * from a foreign realm (template content or shadow root from an iframe + * document) is an instance of the foreign realm's DocumentFragment, not + * the parent realm's, so the check returned false and the template- + * content / shadow-root recursion was silently skipped. The attacker + * payload inside survived untouched. + * + * The realm-independent replacement reads `nodeType` through the cached + * Node.prototype getter and compares to the DOCUMENT_FRAGMENT_NODE + * constant (11). nodeType is a numeric value resolved from the node's + * internal slot, identical across realms for the same kind of node. + * + * @param value object to check + * @return true if value is a DocumentFragment-shaped node from any realm + */ + const _isDocumentFragment = function _isDocumentFragment(value) { + if (!getNodeType || typeof value !== 'object' || value === null) { + return false; + } + try { + return getNodeType(value) === NODE_TYPE.documentFragment; + } catch (_) { + return false; + } }; /** * Checks whether the given object is a DOM node, including nodes that @@ -1127,8 +1228,14 @@ _forceRemove(currentNode); return true; } - /* Check whether element has a valid namespace */ - if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) { + /* Check whether element has a valid namespace. + Realm-safe check (GHSA-hpcv-96wg-7vj8): use the cached Node.prototype + nodeType getter rather than `instanceof Element`, which is realm- + bound and short-circuits to false for any node minted in a different + realm — letting a foreign-realm element with a forbidden namespace + slip past the namespace check entirely. */ + const nt = getNodeType ? getNodeType(currentNode) : currentNode.nodeType; + if (nt === NODE_TYPE.element && !_checkValidNamespace(currentNode)) { _forceRemove(currentNode); return true; } @@ -1355,8 +1462,11 @@ _sanitizeElements(shadowNode); /* Check attributes next */ _sanitizeAttributes(shadowNode); - /* Deep shadow DOM detected */ - if (shadowNode.content instanceof DocumentFragment) { + /* Deep shadow DOM detected. + Realm-safe check (GHSA-hpcv-96wg-7vj8): use nodeType against the + DOCUMENT_FRAGMENT_NODE constant rather than instanceof, so we + recurse into <template>.content from foreign realms too. */ + if (_isDocumentFragment(shadowNode.content)) { _sanitizeShadowDOM2(shadowNode.content); } } @@ -1380,21 +1490,42 @@ * existing _sanitizeShadowDOM template-content recursion) stay * untouched — string-input paths are not affected. * + * DOM-Clobbering hardening: HTMLFormElement carries the WebIDL + * [LegacyOverrideBuiltIns] extended attribute, so a descendant element + * named `nodeType`, `shadowRoot`, or `childNodes` shadows the matching + * prototype getter on the form. Reading those properties directly off + * the node would let an attacker steer this walk past shadow hosts + * (e.g. <input name="childNodes"> collapses the form's child list to + * the input itself, so descent stops dead and any shadow root deeper + * in the subtree is never sanitized). Every property access here is + * therefore routed through the cached prototype getter; the form's + * named-property getter cannot intercept those reads. + * * @param root the subtree root to walk for attached shadow roots */ const _sanitizeAttachedShadowRoots2 = function _sanitizeAttachedShadowRoots(root) { - if (root.nodeType === NODE_TYPE.element && root.shadowRoot instanceof DocumentFragment) { - const sr = root.shadowRoot; - // Recurse first so that nested shadow roots are reached even if - // _sanitizeShadowDOM removes hosts at this level. - _sanitizeAttachedShadowRoots2(sr); - _sanitizeShadowDOM2(sr); + const nodeType = getNodeType ? getNodeType(root) : root.nodeType; + if (nodeType === NODE_TYPE.element) { + const sr = getShadowRoot ? getShadowRoot(root) : root.shadowRoot; + // Realm-safe check (GHSA-hpcv-96wg-7vj8): use nodeType-based + // detection rather than `instanceof DocumentFragment`, which is + // realm-bound and silently skipped shadow roots whose host element + // belonged to a foreign realm (e.g. iframe.contentDocument + // attachShadow). A foreign-realm ShadowRoot extends the foreign + // realm's DocumentFragment, not ours, so the old instanceof check + // returned false and the shadow subtree was never walked. + if (_isDocumentFragment(sr)) { + // Recurse first so that nested shadow roots are reached even if + // _sanitizeShadowDOM removes hosts at this level. + _sanitizeAttachedShadowRoots2(sr); + _sanitizeShadowDOM2(sr); + } } // Snapshot children before recursing. Sanitization of one subtree // (e.g. via an uponSanitizeShadowNode hook) may detach siblings, // and naive nextSibling traversal would silently skip the rest of // the list once a node is detached. - const childNodes = root.childNodes; + const childNodes = getChildNodes ? getChildNodes(root) : root.childNodes; if (!childNodes) { return; } @@ -1442,14 +1573,31 @@ IN_PLACE = false; } if (IN_PLACE) { - /* Do some early pre-sanitization to avoid unsafe root nodes */ - const nn = dirty.nodeName; + /* Do some early pre-sanitization to avoid unsafe root nodes. + Read nodeName through the cached prototype getter — a clobbering + child named "nodeName" on the form root would otherwise shadow + the property and let this check skip the root-allowlist + validation entirely. */ + const nn = getNodeName ? getNodeName(dirty) : dirty.nodeName; if (typeof nn === 'string') { const tagName = transformCaseFunc(nn); if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) { throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place'); } } + /* Pre-flight the root through _isClobbered. The iterator-driven + removal path can not detach a parent-less root: _forceRemove + falls through to Element.prototype.remove(), which per spec + is a no-op on a node with no parent. A clobbered root would + then survive the main loop with its attributes uninspected, + because _sanitizeAttributes early-returns on _isClobbered. The + result would be an attacker-controlled form, complete with any + event-handler attributes the caller passed in, handed back to + the application unsanitized. Refuse to sanitize such a root + the same way we refuse a forbidden tag. GHSA-r47g-fvhr-h676. */ + if (_isClobbered(dirty)) { + throw typeErrorCreate('root node is clobbered and cannot be sanitized in-place'); + } /* Sanitize attached shadow roots before the main iterator runs. The iterator does not descend into shadow trees. */ _sanitizeAttachedShadowRoots2(dirty); @@ -1469,7 +1617,9 @@ } /* Clonable shadow roots are deep-cloned by importNode(); sanitize them before the main iterator runs, since the iterator does not - descend into shadow trees. */ + descend into shadow trees. The walk routes every read through a + cached prototype getter so clobbering descendants on a form root + cannot hide a shadow host from this pass. */ _sanitizeAttachedShadowRoots2(importedNode); } else { /* Exit directly if we have nothing to do */ @@ -1497,8 +1647,11 @@ _sanitizeElements(currentNode); /* Check attributes next */ _sanitizeAttributes(currentNode); - /* Shadow DOM detected, sanitize it */ - if (currentNode.content instanceof DocumentFragment) { + /* Shadow DOM detected, sanitize it. + Realm-safe check (GHSA-hpcv-96wg-7vj8): nodeType-based detection + instead of instanceof, so foreign-realm <template>.content is + walked correctly. */ + if (_isDocumentFragment(currentNode.content)) { _sanitizeShadowDOM2(currentNode.content); } }
dist/purify.js.map+1 −1 modifieddist/purify.min.js+2 −2 modified@@ -1,3 +1,3 @@ -/*! @license DOMPurify 3.4.5 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.5/LICENSE */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).DOMPurify=t()}(this,function(){"use strict";function e(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);n<t;n++)o[n]=e[n];return o}function t(t,n){return function(e){if(Array.isArray(e))return e}(t)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var o,r,i,a,l=[],c=!0,s=!1;try{if(i=(n=n.call(e)).next,0===t);else for(;!(c=(o=i.call(n)).done)&&(l.push(o.value),l.length!==t);c=!0);}catch(e){s=!0,r=e}finally{try{if(!c&&null!=n.return&&(a=n.return(),Object(a)!==a))return}finally{if(s)throw r}}return l}}(t,n)||function(t,n){if(t){if("string"==typeof t)return e(t,n);var o={}.toString.call(t).slice(8,-1);return"Object"===o&&t.constructor&&(o=t.constructor.name),"Map"===o||"Set"===o?Array.from(t):"Arguments"===o||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(o)?e(t,n):void 0}}(t,n)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}const n=Object.entries,o=Object.setPrototypeOf,r=Object.isFrozen,i=Object.getPrototypeOf,a=Object.getOwnPropertyDescriptor;let l=Object.freeze,c=Object.seal,s=Object.create,u="undefined"!=typeof Reflect&&Reflect,f=u.apply,m=u.construct;l||(l=function(e){return e}),c||(c=function(e){return e}),f||(f=function(e,t){for(var n=arguments.length,o=new Array(n>2?n-2:0),r=2;r<n;r++)o[r-2]=arguments[r];return e.apply(t,o)}),m||(m=function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),o=1;o<t;o++)n[o-1]=arguments[o];return new e(...n)});const p=L(Array.prototype.forEach),d=L(Array.prototype.lastIndexOf),h=L(Array.prototype.pop),g=L(Array.prototype.push),y=L(Array.prototype.splice),T=Array.isArray,b=L(String.prototype.toLowerCase),A=L(String.prototype.toString),S=L(String.prototype.match),E=L(String.prototype.replace),N=L(String.prototype.indexOf),_=L(String.prototype.trim),O=L(Number.prototype.toString),D=L(Boolean.prototype.toString),R="undefined"==typeof BigInt?null:L(BigInt.prototype.toString),w="undefined"==typeof Symbol?null:L(Symbol.prototype.toString),I=L(Object.prototype.hasOwnProperty),v=L(Object.prototype.toString),C=L(RegExp.prototype.test),x=(k=TypeError,function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return m(k,t)});var k;function L(e){return function(t){t instanceof RegExp&&(t.lastIndex=0);for(var n=arguments.length,o=new Array(n>1?n-1:0),r=1;r<n;r++)o[r-1]=arguments[r];return f(e,t,o)}}function M(e,t){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:b;if(o&&o(e,null),!T(t))return e;let i=t.length;for(;i--;){let o=t[i];if("string"==typeof o){const e=n(o);e!==o&&(r(t)||(t[i]=e),o=e)}e[o]=!0}return e}function F(e){for(let t=0;t<e.length;t++){I(e,t)||(e[t]=null)}return e}function z(e){const o=s(null);for(const i of n(e)){var r=t(i,2);const n=r[0],a=r[1];I(e,n)&&(T(a)?o[n]=F(a):a&&"object"==typeof a&&a.constructor===Object?o[n]=z(a):o[n]=a)}return o}function P(e,t){for(;null!==e;){const n=a(e,t);if(n){if(n.get)return L(n.get);if("function"==typeof n.value)return L(n.value)}e=i(e)}return function(){return null}}const U=l(["a","abbr","acronym","address","area","article","aside","audio","b","bdi","bdo","big","blink","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","content","data","datalist","dd","decorator","del","details","dfn","dialog","dir","div","dl","dt","element","em","fieldset","figcaption","figure","font","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","img","input","ins","kbd","label","legend","li","main","map","mark","marquee","menu","menuitem","meter","nav","nobr","ol","optgroup","option","output","p","picture","pre","progress","q","rp","rt","ruby","s","samp","search","section","select","shadow","slot","small","source","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","tr","track","tt","u","ul","var","video","wbr"]),H=l(["svg","a","altglyph","altglyphdef","altglyphitem","animatecolor","animatemotion","animatetransform","circle","clippath","defs","desc","ellipse","enterkeyhint","exportparts","filter","font","g","glyph","glyphref","hkern","image","inputmode","line","lineargradient","marker","mask","metadata","mpath","part","path","pattern","polygon","polyline","radialgradient","rect","stop","style","switch","symbol","text","textpath","title","tref","tspan","view","vkern"]),B=l(["feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence"]),G=l(["animate","color-profile","cursor","discard","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","foreignobject","hatch","hatchpath","mesh","meshgradient","meshpatch","meshrow","missing-glyph","script","set","solidcolor","unknown","use"]),j=l(["math","menclose","merror","mfenced","mfrac","mglyph","mi","mlabeledtr","mmultiscripts","mn","mo","mover","mpadded","mphantom","mroot","mrow","ms","mspace","msqrt","mstyle","msub","msup","msubsup","mtable","mtd","mtext","mtr","munder","munderover","mprescripts"]),W=l(["maction","maligngroup","malignmark","mlongdiv","mscarries","mscarry","msgroup","mstack","msline","msrow","semantics","annotation","annotation-xml","mprescripts","none"]),Y=l(["#text"]),X=l(["accept","action","align","alt","autocapitalize","autocomplete","autopictureinpicture","autoplay","background","bgcolor","border","capture","cellpadding","cellspacing","checked","cite","class","clear","color","cols","colspan","command","commandfor","controls","controlslist","coords","crossorigin","datetime","decoding","default","dir","disabled","disablepictureinpicture","disableremoteplayback","download","draggable","enctype","enterkeyhint","exportparts","face","for","headers","height","hidden","high","href","hreflang","id","inert","inputmode","integrity","ismap","kind","label","lang","list","loading","loop","low","max","maxlength","media","method","min","minlength","multiple","muted","name","nonce","noshade","novalidate","nowrap","open","optimum","part","pattern","placeholder","playsinline","popover","popovertarget","popovertargetaction","poster","preload","pubdate","radiogroup","readonly","rel","required","rev","reversed","role","rows","rowspan","spellcheck","scope","selected","shape","size","sizes","slot","span","srclang","start","src","srcset","step","style","summary","tabindex","title","translate","type","usemap","valign","value","width","wrap","xmlns"]),q=l(["accent-height","accumulate","additive","alignment-baseline","amplitude","ascent","attributename","attributetype","azimuth","basefrequency","baseline-shift","begin","bias","by","class","clip","clippathunits","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","cx","cy","d","dx","dy","diffuseconstant","direction","display","divisor","dur","edgemode","elevation","end","exponent","fill","fill-opacity","fill-rule","filter","filterunits","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","fx","fy","g1","g2","glyph-name","glyphref","gradientunits","gradienttransform","height","href","id","image-rendering","in","in2","intercept","k","k1","k2","k3","k4","kerning","keypoints","keysplines","keytimes","lang","lengthadjust","letter-spacing","kernelmatrix","kernelunitlength","lighting-color","local","marker-end","marker-mid","marker-start","markerheight","markerunits","markerwidth","maskcontentunits","maskunits","max","mask","mask-type","media","method","mode","min","name","numoctaves","offset","operator","opacity","order","orient","orientation","origin","overflow","paint-order","path","pathlength","patterncontentunits","patterntransform","patternunits","points","preservealpha","preserveaspectratio","primitiveunits","r","rx","ry","radius","refx","refy","repeatcount","repeatdur","restart","result","rotate","scale","seed","shape-rendering","slope","specularconstant","specularexponent","spreadmethod","startoffset","stddeviation","stitchtiles","stop-color","stop-opacity","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke","stroke-width","style","surfacescale","systemlanguage","tabindex","tablevalues","targetx","targety","transform","transform-origin","text-anchor","text-decoration","text-rendering","textlength","type","u1","u2","unicode","values","viewbox","visibility","version","vert-adv-y","vert-origin-x","vert-origin-y","width","word-spacing","wrap","writing-mode","xchannelselector","ychannelselector","x","x1","x2","xmlns","y","y1","y2","z","zoomandpan"]),$=l(["accent","accentunder","align","bevelled","close","columnalign","columnlines","columnspacing","columnspan","denomalign","depth","dir","display","displaystyle","encoding","fence","frame","height","href","id","largeop","length","linethickness","lquote","lspace","mathbackground","mathcolor","mathsize","mathvariant","maxsize","minsize","movablelimits","notation","numalign","open","rowalign","rowlines","rowspacing","rowspan","rspace","rquote","scriptlevel","scriptminsize","scriptsizemultiplier","selection","separator","separators","stretchy","subscriptshift","supscriptshift","symmetric","voffset","width","xmlns"]),K=l(["xlink:href","xml:id","xlink:title","xml:space","xmlns:xlink"]),V=c(/{{[\w\W]*|^[\w\W]*}}/g),Z=c(/<%[\w\W]*|^[\w\W]*%>/g),J=c(/\${[\w\W]*/g),Q=c(/^data-[\-\w.\u00B7-\uFFFF]+$/),ee=c(/^aria-[\-\w]+$/),te=c(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),ne=c(/^(?:\w+script|data):/i),oe=c(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),re=c(/^html$/i),ie=c(/^[a-z][.\w]*(-[.\w]+)+$/i),ae=1,le=3,ce=7,se=8,ue=9,fe=function(){return"undefined"==typeof window?null:window};var me=function e(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:fe();const o=t=>e(t);if(o.version="3.4.5",o.removed=[],!t||!t.document||t.document.nodeType!==ue||!t.Element)return o.isSupported=!1,o;let r=t.document;const i=r,a=i.currentScript,c=t.DocumentFragment,u=t.HTMLTemplateElement,f=t.Node,m=t.Element,k=t.NodeFilter,L=t.NamedNodeMap,F=void 0===L?t.NamedNodeMap||t.MozNamedAttrMap:L,me=t.HTMLFormElement,pe=t.DOMParser,de=t.trustedTypes,he=m.prototype,ge=P(he,"cloneNode"),ye=P(he,"remove"),Te=P(he,"nextSibling"),be=P(he,"childNodes"),Ae=P(he,"parentNode"),Se=f&&f.prototype?P(f.prototype,"nodeType"):null;if("function"==typeof u){const e=r.createElement("template");e.content&&e.content.ownerDocument&&(r=e.content.ownerDocument)}let Ee,Ne="";const _e=r,Oe=_e.implementation,De=_e.createNodeIterator,Re=_e.createDocumentFragment,we=_e.getElementsByTagName,Ie=i.importNode;let ve={afterSanitizeAttributes:[],afterSanitizeElements:[],afterSanitizeShadowDOM:[],beforeSanitizeAttributes:[],beforeSanitizeElements:[],beforeSanitizeShadowDOM:[],uponSanitizeAttribute:[],uponSanitizeElement:[],uponSanitizeShadowNode:[]};o.isSupported="function"==typeof n&&"function"==typeof Ae&&Oe&&void 0!==Oe.createHTMLDocument;const Ce=V,xe=Z,ke=J,Le=Q,Me=ee,Fe=ne,ze=oe,Pe=ie;let Ue=te,He=null;const Be=M({},[...U,...H,...B,...j,...Y]);let Ge=null;const je=M({},[...X,...q,...$,...K]);let We=Object.seal(s(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),Ye=null,Xe=null;const qe=Object.seal(s(null,{tagCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeCheck:{writable:!0,configurable:!1,enumerable:!0,value:null}}));let $e=!0,Ke=!0,Ve=!1,Ze=!0,Je=!1,Qe=!0,et=!1,tt=!1,nt=!1,ot=!1,rt=!1,it=!1,at=!0,lt=!1;const ct="user-content-";let st=!0,ut=!1,ft={},mt=null;const pt=M({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let dt=null;const ht=M({},["audio","video","img","source","image","track"]);let gt=null;const yt=M({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),Tt="http://www.w3.org/1998/Math/MathML",bt="http://www.w3.org/2000/svg",At="http://www.w3.org/1999/xhtml";let St=At,Et=!1,Nt=null;const _t=M({},[Tt,bt,At],A);let Ot=M({},["mi","mo","mn","ms","mtext"]),Dt=M({},["annotation-xml"]);const Rt=M({},["title","style","font","a","script"]);let wt=null;const It=["application/xhtml+xml","text/html"];let vt=null,Ct=null;const xt=r.createElement("form"),kt=function(e){return e instanceof RegExp||e instanceof Function},Lt=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(Ct&&Ct===e)return;e&&"object"==typeof e||(e={}),e=z(e),wt=-1===It.indexOf(e.PARSER_MEDIA_TYPE)?"text/html":e.PARSER_MEDIA_TYPE,vt="application/xhtml+xml"===wt?A:b,He=I(e,"ALLOWED_TAGS")&&T(e.ALLOWED_TAGS)?M({},e.ALLOWED_TAGS,vt):Be,Ge=I(e,"ALLOWED_ATTR")&&T(e.ALLOWED_ATTR)?M({},e.ALLOWED_ATTR,vt):je,Nt=I(e,"ALLOWED_NAMESPACES")&&T(e.ALLOWED_NAMESPACES)?M({},e.ALLOWED_NAMESPACES,A):_t,gt=I(e,"ADD_URI_SAFE_ATTR")&&T(e.ADD_URI_SAFE_ATTR)?M(z(yt),e.ADD_URI_SAFE_ATTR,vt):yt,dt=I(e,"ADD_DATA_URI_TAGS")&&T(e.ADD_DATA_URI_TAGS)?M(z(ht),e.ADD_DATA_URI_TAGS,vt):ht,mt=I(e,"FORBID_CONTENTS")&&T(e.FORBID_CONTENTS)?M({},e.FORBID_CONTENTS,vt):pt,Ye=I(e,"FORBID_TAGS")&&T(e.FORBID_TAGS)?M({},e.FORBID_TAGS,vt):z({}),Xe=I(e,"FORBID_ATTR")&&T(e.FORBID_ATTR)?M({},e.FORBID_ATTR,vt):z({}),ft=!!I(e,"USE_PROFILES")&&(e.USE_PROFILES&&"object"==typeof e.USE_PROFILES?z(e.USE_PROFILES):e.USE_PROFILES),$e=!1!==e.ALLOW_ARIA_ATTR,Ke=!1!==e.ALLOW_DATA_ATTR,Ve=e.ALLOW_UNKNOWN_PROTOCOLS||!1,Ze=!1!==e.ALLOW_SELF_CLOSE_IN_ATTR,Je=e.SAFE_FOR_TEMPLATES||!1,Qe=!1!==e.SAFE_FOR_XML,et=e.WHOLE_DOCUMENT||!1,ot=e.RETURN_DOM||!1,rt=e.RETURN_DOM_FRAGMENT||!1,it=e.RETURN_TRUSTED_TYPE||!1,nt=e.FORCE_BODY||!1,at=!1!==e.SANITIZE_DOM,lt=e.SANITIZE_NAMED_PROPS||!1,st=!1!==e.KEEP_CONTENT,ut=e.IN_PLACE||!1,Ue=function(e){try{return C(e,""),!0}catch(e){return!1}}(e.ALLOWED_URI_REGEXP)?e.ALLOWED_URI_REGEXP:te,St="string"==typeof e.NAMESPACE?e.NAMESPACE:At,Ot=I(e,"MATHML_TEXT_INTEGRATION_POINTS")&&e.MATHML_TEXT_INTEGRATION_POINTS&&"object"==typeof e.MATHML_TEXT_INTEGRATION_POINTS?z(e.MATHML_TEXT_INTEGRATION_POINTS):M({},["mi","mo","mn","ms","mtext"]),Dt=I(e,"HTML_INTEGRATION_POINTS")&&e.HTML_INTEGRATION_POINTS&&"object"==typeof e.HTML_INTEGRATION_POINTS?z(e.HTML_INTEGRATION_POINTS):M({},["annotation-xml"]);const t=I(e,"CUSTOM_ELEMENT_HANDLING")&&e.CUSTOM_ELEMENT_HANDLING&&"object"==typeof e.CUSTOM_ELEMENT_HANDLING?z(e.CUSTOM_ELEMENT_HANDLING):s(null);if(We=s(null),I(t,"tagNameCheck")&&kt(t.tagNameCheck)&&(We.tagNameCheck=t.tagNameCheck),I(t,"attributeNameCheck")&&kt(t.attributeNameCheck)&&(We.attributeNameCheck=t.attributeNameCheck),I(t,"allowCustomizedBuiltInElements")&&"boolean"==typeof t.allowCustomizedBuiltInElements&&(We.allowCustomizedBuiltInElements=t.allowCustomizedBuiltInElements),Je&&(Ke=!1),rt&&(ot=!0),ft&&(He=M({},Y),Ge=s(null),!0===ft.html&&(M(He,U),M(Ge,X)),!0===ft.svg&&(M(He,H),M(Ge,q),M(Ge,K)),!0===ft.svgFilters&&(M(He,B),M(Ge,q),M(Ge,K)),!0===ft.mathMl&&(M(He,j),M(Ge,$),M(Ge,K))),qe.tagCheck=null,qe.attributeCheck=null,I(e,"ADD_TAGS")&&("function"==typeof e.ADD_TAGS?qe.tagCheck=e.ADD_TAGS:T(e.ADD_TAGS)&&(He===Be&&(He=z(He)),M(He,e.ADD_TAGS,vt))),I(e,"ADD_ATTR")&&("function"==typeof e.ADD_ATTR?qe.attributeCheck=e.ADD_ATTR:T(e.ADD_ATTR)&&(Ge===je&&(Ge=z(Ge)),M(Ge,e.ADD_ATTR,vt))),I(e,"ADD_URI_SAFE_ATTR")&&T(e.ADD_URI_SAFE_ATTR)&&M(gt,e.ADD_URI_SAFE_ATTR,vt),I(e,"FORBID_CONTENTS")&&T(e.FORBID_CONTENTS)&&(mt===pt&&(mt=z(mt)),M(mt,e.FORBID_CONTENTS,vt)),I(e,"ADD_FORBID_CONTENTS")&&T(e.ADD_FORBID_CONTENTS)&&(mt===pt&&(mt=z(mt)),M(mt,e.ADD_FORBID_CONTENTS,vt)),st&&(He["#text"]=!0),et&&M(He,["html","head","body"]),He.table&&(M(He,["tbody"]),delete Ye.tbody),e.TRUSTED_TYPES_POLICY){if("function"!=typeof e.TRUSTED_TYPES_POLICY.createHTML)throw x('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if("function"!=typeof e.TRUSTED_TYPES_POLICY.createScriptURL)throw x('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');Ee=e.TRUSTED_TYPES_POLICY,Ne=Ee.createHTML("")}else void 0===Ee&&(Ee=function(e,t){if("object"!=typeof e||"function"!=typeof e.createPolicy)return null;let n=null;const o="data-tt-policy-suffix";t&&t.hasAttribute(o)&&(n=t.getAttribute(o));const r="dompurify"+(n?"#"+n:"");try{return e.createPolicy(r,{createHTML:e=>e,createScriptURL:e=>e})}catch(e){return console.warn("TrustedTypes policy "+r+" could not be created."),null}}(de,a)),null!==Ee&&"string"==typeof Ne&&(Ne=Ee.createHTML(""));l&&l(e),Ct=e},Mt=M({},[...H,...B,...G]),Ft=M({},[...j,...W]),zt=function(e){g(o.removed,{element:e});try{Ae(e).removeChild(e)}catch(t){ye(e)}},Pt=function(e,t){try{g(o.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){g(o.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e)if(ot||rt)try{zt(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},Ut=function(e){let t=null,n=null;if(nt)e="<remove></remove>"+e;else{const t=S(e,/^[\r\n\t ]+/);n=t&&t[0]}"application/xhtml+xml"===wt&&St===At&&(e='<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>'+e+"</body></html>");const o=Ee?Ee.createHTML(e):e;if(St===At)try{t=(new pe).parseFromString(o,wt)}catch(e){}if(!t||!t.documentElement){t=Oe.createDocument(St,"template",null);try{t.documentElement.innerHTML=Et?Ne:o}catch(e){}}const i=t.body||t.documentElement;return e&&n&&i.insertBefore(r.createTextNode(n),i.childNodes[0]||null),St===At?we.call(t,et?"html":"body")[0]:et?t.documentElement:i},Ht=function(e){return De.call(e.ownerDocument||e,e,k.SHOW_ELEMENT|k.SHOW_COMMENT|k.SHOW_TEXT|k.SHOW_PROCESSING_INSTRUCTION|k.SHOW_CDATA_SECTION,null)},Bt=function(e){e.normalize();const t=De.call(e.ownerDocument||e,e,k.SHOW_TEXT|k.SHOW_COMMENT|k.SHOW_CDATA_SECTION|k.SHOW_PROCESSING_INSTRUCTION,null);let n=t.nextNode();for(;n;){let e=n.data;p([Ce,xe,ke],t=>{e=E(e,t," ")}),n.data=e,n=t.nextNode()}},Gt=function(e){return e instanceof me&&("string"!=typeof e.nodeName||"string"!=typeof e.textContent||"function"!=typeof e.removeChild||!(e.attributes instanceof F)||"function"!=typeof e.removeAttribute||"function"!=typeof e.setAttribute||"string"!=typeof e.namespaceURI||"function"!=typeof e.insertBefore||"function"!=typeof e.hasChildNodes)},jt=function(e){if(!Se||"object"!=typeof e||null===e)return!1;try{return"number"==typeof Se(e)}catch(e){return!1}};function Wt(e,t,n){p(e,e=>{e.call(o,t,n,Ct)})}const Yt=function(e){let t=null;if(Wt(ve.beforeSanitizeElements,e,null),Gt(e))return zt(e),!0;const n=vt(e.nodeName);if(Wt(ve.uponSanitizeElement,e,{tagName:n,allowedTags:He}),Qe&&e.hasChildNodes()&&!jt(e.firstElementChild)&&C(/<[/\w!]/g,e.innerHTML)&&C(/<[/\w!]/g,e.textContent))return zt(e),!0;if(Qe&&e.namespaceURI===At&&"style"===n&&jt(e.firstElementChild))return zt(e),!0;if(e.nodeType===ce)return zt(e),!0;if(Qe&&e.nodeType===se&&C(/<[/\w]/g,e.data))return zt(e),!0;if(Ye[n]||!(qe.tagCheck instanceof Function&&qe.tagCheck(n))&&!He[n]){if(!Ye[n]&&$t(n)){if(We.tagNameCheck instanceof RegExp&&C(We.tagNameCheck,n))return!1;if(We.tagNameCheck instanceof Function&&We.tagNameCheck(n))return!1}if(st&&!mt[n]){const t=Ae(e)||e.parentNode,n=be(e)||e.childNodes;if(n&&t){for(let o=n.length-1;o>=0;--o){const r=ge(n[o],!0);t.insertBefore(r,Te(e))}}}return zt(e),!0}return e instanceof m&&!function(e){let t=Ae(e);t&&t.tagName||(t={namespaceURI:St,tagName:"template"});const n=b(e.tagName),o=b(t.tagName);return!!Nt[e.namespaceURI]&&(e.namespaceURI===bt?t.namespaceURI===At?"svg"===n:t.namespaceURI===Tt?"svg"===n&&("annotation-xml"===o||Ot[o]):Boolean(Mt[n]):e.namespaceURI===Tt?t.namespaceURI===At?"math"===n:t.namespaceURI===bt?"math"===n&&Dt[o]:Boolean(Ft[n]):e.namespaceURI===At?!(t.namespaceURI===bt&&!Dt[o])&&!(t.namespaceURI===Tt&&!Ot[o])&&!Ft[n]&&(Rt[n]||!Mt[n]):!("application/xhtml+xml"!==wt||!Nt[e.namespaceURI]))}(e)?(zt(e),!0):"noscript"!==n&&"noembed"!==n&&"noframes"!==n||!C(/<\/no(script|embed|frames)/i,e.innerHTML)?(Je&&e.nodeType===le&&(t=e.textContent,p([Ce,xe,ke],e=>{t=E(t,e," ")}),e.textContent!==t&&(g(o.removed,{element:e.cloneNode()}),e.textContent=t)),Wt(ve.afterSanitizeElements,e,null),!1):(zt(e),!0)},Xt=function(e,t,n){if(Xe[t])return!1;if(at&&("id"===t||"name"===t)&&(n in r||n in xt))return!1;const o=Ge[t]||qe.attributeCheck instanceof Function&&qe.attributeCheck(t,e);if(Ke&&!Xe[t]&&C(Le,t));else if($e&&C(Me,t));else if(!o||Xe[t]){if(!($t(e)&&(We.tagNameCheck instanceof RegExp&&C(We.tagNameCheck,e)||We.tagNameCheck instanceof Function&&We.tagNameCheck(e))&&(We.attributeNameCheck instanceof RegExp&&C(We.attributeNameCheck,t)||We.attributeNameCheck instanceof Function&&We.attributeNameCheck(t,e))||"is"===t&&We.allowCustomizedBuiltInElements&&(We.tagNameCheck instanceof RegExp&&C(We.tagNameCheck,n)||We.tagNameCheck instanceof Function&&We.tagNameCheck(n))))return!1}else if(gt[t]);else if(C(Ue,E(n,ze,"")));else if("src"!==t&&"xlink:href"!==t&&"href"!==t||"script"===e||0!==N(n,"data:")||!dt[e]){if(Ve&&!C(Fe,E(n,ze,"")));else if(n)return!1}else;return!0},qt=M({},["annotation-xml","color-profile","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","missing-glyph"]),$t=function(e){return!qt[b(e)]&&C(Pe,e)},Kt=function(e){Wt(ve.beforeSanitizeAttributes,e,null);const t=e.attributes;if(!t||Gt(e))return;const n={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:Ge,forceKeepAttr:void 0};let r=t.length;for(;r--;){const i=t[r],a=i.name,l=i.namespaceURI,c=i.value,s=vt(a),u=c;let f="value"===a?u:_(u);if(n.attrName=s,n.attrValue=f,n.keepAttr=!0,n.forceKeepAttr=void 0,Wt(ve.uponSanitizeAttribute,e,n),f=n.attrValue,!lt||"id"!==s&&"name"!==s||0===N(f,ct)||(Pt(a,e),f=ct+f),Qe&&C(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i,f)){Pt(a,e);continue}if("attributename"===s&&S(f,"href")){Pt(a,e);continue}if(n.forceKeepAttr)continue;if(!n.keepAttr){Pt(a,e);continue}if(!Ze&&C(/\/>/i,f)){Pt(a,e);continue}Je&&p([Ce,xe,ke],e=>{f=E(f,e," ")});const m=vt(e.nodeName);if(Xt(m,s,f)){if(Ee&&"object"==typeof de&&"function"==typeof de.getAttributeType)if(l);else switch(de.getAttributeType(m,s)){case"TrustedHTML":f=Ee.createHTML(f);break;case"TrustedScriptURL":f=Ee.createScriptURL(f)}if(f!==u)try{l?e.setAttributeNS(l,a,f):e.setAttribute(a,f),Gt(e)?zt(e):h(o.removed)}catch(t){Pt(a,e)}}else Pt(a,e)}Wt(ve.afterSanitizeAttributes,e,null)},Vt=function(e){let t=null;const n=Ht(e);for(Wt(ve.beforeSanitizeShadowDOM,e,null);t=n.nextNode();)Wt(ve.uponSanitizeShadowNode,t,null),Yt(t),Kt(t),t.content instanceof c&&Vt(t.content);Wt(ve.afterSanitizeShadowDOM,e,null)},Zt=function(e){if(e.nodeType===ae&&e.shadowRoot instanceof c){const t=e.shadowRoot;Zt(t),Vt(t)}const t=e.childNodes;if(!t)return;const n=[];p(t,e=>{g(n,e)});for(const e of n)Zt(e)};return o.sanitize=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=null,r=null,a=null,l=null;if(Et=!e,Et&&(e="\x3c!--\x3e"),"string"!=typeof e&&!jt(e)&&"string"!=typeof(e=function(e){switch(typeof e){case"string":return e;case"number":return O(e);case"boolean":return D(e);case"bigint":return R?R(e):"0";case"symbol":return w?w(e):"Symbol()";case"undefined":default:return v(e);case"function":case"object":{if(null===e)return v(e);const t=e,n=P(t,"toString");if("function"==typeof n){const e=n(t);return"string"==typeof e?e:v(e)}return v(e)}}}(e)))throw x("dirty is not a string, aborting");if(!o.isSupported)return e;if(tt||Lt(t),o.removed=[],"string"==typeof e&&(ut=!1),ut){const t=e.nodeName;if("string"==typeof t){const e=vt(t);if(!He[e]||Ye[e])throw x("root node is forbidden and cannot be sanitized in-place")}Zt(e)}else if(jt(e))n=Ut("\x3c!----\x3e"),r=n.ownerDocument.importNode(e,!0),r.nodeType===ae&&"BODY"===r.nodeName||"HTML"===r.nodeName?n=r:n.appendChild(r),Zt(r);else{if(!ot&&!Je&&!et&&-1===e.indexOf("<"))return Ee&&it?Ee.createHTML(e):e;if(n=Ut(e),!n)return ot?null:it?Ne:""}n&&nt&&zt(n.firstChild);const s=Ht(ut?e:n);for(;a=s.nextNode();)Yt(a),Kt(a),a.content instanceof c&&Vt(a.content);if(ut)return Je&&Bt(e),e;if(ot){if(Je&&Bt(n),rt)for(l=Re.call(n.ownerDocument);n.firstChild;)l.appendChild(n.firstChild);else l=n;return(Ge.shadowroot||Ge.shadowrootmode)&&(l=Ie.call(i,l,!0)),l}let u=et?n.outerHTML:n.innerHTML;return et&&He["!doctype"]&&n.ownerDocument&&n.ownerDocument.doctype&&n.ownerDocument.doctype.name&&C(re,n.ownerDocument.doctype.name)&&(u="<!DOCTYPE "+n.ownerDocument.doctype.name+">\n"+u),Je&&p([Ce,xe,ke],e=>{u=E(u,e," ")}),Ee&&it?Ee.createHTML(u):u},o.setConfig=function(){Lt(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),tt=!0},o.clearConfig=function(){Ct=null,tt=!1},o.isValidAttribute=function(e,t,n){Ct||Lt({});const o=vt(e),r=vt(t);return Xt(o,r,n)},o.addHook=function(e,t){"function"==typeof t&&g(ve[e],t)},o.removeHook=function(e,t){if(void 0!==t){const n=d(ve[e],t);return-1===n?void 0:y(ve[e],n,1)[0]}return h(ve[e])},o.removeHooks=function(e){ve[e]=[]},o.removeAllHooks=function(){ve={afterSanitizeAttributes:[],afterSanitizeElements:[],afterSanitizeShadowDOM:[],beforeSanitizeAttributes:[],beforeSanitizeElements:[],beforeSanitizeShadowDOM:[],uponSanitizeAttribute:[],uponSanitizeElement:[],uponSanitizeShadowNode:[]}},o}();return me}); +/*! @license DOMPurify 3.4.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.6/LICENSE */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).DOMPurify=t()}(this,function(){"use strict";function e(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);n<t;n++)o[n]=e[n];return o}function t(t,n){return function(e){if(Array.isArray(e))return e}(t)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var o,r,i,a,l=[],c=!0,s=!1;try{if(i=(n=n.call(e)).next,0===t);else for(;!(c=(o=i.call(n)).done)&&(l.push(o.value),l.length!==t);c=!0);}catch(e){s=!0,r=e}finally{try{if(!c&&null!=n.return&&(a=n.return(),Object(a)!==a))return}finally{if(s)throw r}}return l}}(t,n)||function(t,n){if(t){if("string"==typeof t)return e(t,n);var o={}.toString.call(t).slice(8,-1);return"Object"===o&&t.constructor&&(o=t.constructor.name),"Map"===o||"Set"===o?Array.from(t):"Arguments"===o||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(o)?e(t,n):void 0}}(t,n)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}const n=Object.entries,o=Object.setPrototypeOf,r=Object.isFrozen,i=Object.getPrototypeOf,a=Object.getOwnPropertyDescriptor;let l=Object.freeze,c=Object.seal,s=Object.create,u="undefined"!=typeof Reflect&&Reflect,f=u.apply,m=u.construct;l||(l=function(e){return e}),c||(c=function(e){return e}),f||(f=function(e,t){for(var n=arguments.length,o=new Array(n>2?n-2:0),r=2;r<n;r++)o[r-2]=arguments[r];return e.apply(t,o)}),m||(m=function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),o=1;o<t;o++)n[o-1]=arguments[o];return new e(...n)});const p=L(Array.prototype.forEach),d=L(Array.prototype.lastIndexOf),h=L(Array.prototype.pop),g=L(Array.prototype.push),y=L(Array.prototype.splice),T=Array.isArray,b=L(String.prototype.toLowerCase),A=L(String.prototype.toString),S=L(String.prototype.match),E=L(String.prototype.replace),N=L(String.prototype.indexOf),_=L(String.prototype.trim),O=L(Number.prototype.toString),D=L(Boolean.prototype.toString),R="undefined"==typeof BigInt?null:L(BigInt.prototype.toString),w="undefined"==typeof Symbol?null:L(Symbol.prototype.toString),I=L(Object.prototype.hasOwnProperty),v=L(Object.prototype.toString),C=L(RegExp.prototype.test),x=(k=TypeError,function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return m(k,t)});var k;function L(e){return function(t){t instanceof RegExp&&(t.lastIndex=0);for(var n=arguments.length,o=new Array(n>1?n-1:0),r=1;r<n;r++)o[r-1]=arguments[r];return f(e,t,o)}}function M(e,t){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:b;if(o&&o(e,null),!T(t))return e;let i=t.length;for(;i--;){let o=t[i];if("string"==typeof o){const e=n(o);e!==o&&(r(t)||(t[i]=e),o=e)}e[o]=!0}return e}function z(e){for(let t=0;t<e.length;t++){I(e,t)||(e[t]=null)}return e}function F(e){const o=s(null);for(const i of n(e)){var r=t(i,2);const n=r[0],a=r[1];I(e,n)&&(T(a)?o[n]=z(a):a&&"object"==typeof a&&a.constructor===Object?o[n]=F(a):o[n]=a)}return o}function P(e,t){for(;null!==e;){const n=a(e,t);if(n){if(n.get)return L(n.get);if("function"==typeof n.value)return L(n.value)}e=i(e)}return function(){return null}}const U=l(["a","abbr","acronym","address","area","article","aside","audio","b","bdi","bdo","big","blink","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","content","data","datalist","dd","decorator","del","details","dfn","dialog","dir","div","dl","dt","element","em","fieldset","figcaption","figure","font","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","img","input","ins","kbd","label","legend","li","main","map","mark","marquee","menu","menuitem","meter","nav","nobr","ol","optgroup","option","output","p","picture","pre","progress","q","rp","rt","ruby","s","samp","search","section","select","shadow","slot","small","source","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","tr","track","tt","u","ul","var","video","wbr"]),H=l(["svg","a","altglyph","altglyphdef","altglyphitem","animatecolor","animatemotion","animatetransform","circle","clippath","defs","desc","ellipse","enterkeyhint","exportparts","filter","font","g","glyph","glyphref","hkern","image","inputmode","line","lineargradient","marker","mask","metadata","mpath","part","path","pattern","polygon","polyline","radialgradient","rect","stop","style","switch","symbol","text","textpath","title","tref","tspan","view","vkern"]),B=l(["feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence"]),j=l(["animate","color-profile","cursor","discard","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","foreignobject","hatch","hatchpath","mesh","meshgradient","meshpatch","meshrow","missing-glyph","script","set","solidcolor","unknown","use"]),G=l(["math","menclose","merror","mfenced","mfrac","mglyph","mi","mlabeledtr","mmultiscripts","mn","mo","mover","mpadded","mphantom","mroot","mrow","ms","mspace","msqrt","mstyle","msub","msup","msubsup","mtable","mtd","mtext","mtr","munder","munderover","mprescripts"]),W=l(["maction","maligngroup","malignmark","mlongdiv","mscarries","mscarry","msgroup","mstack","msline","msrow","semantics","annotation","annotation-xml","mprescripts","none"]),Y=l(["#text"]),X=l(["accept","action","align","alt","autocapitalize","autocomplete","autopictureinpicture","autoplay","background","bgcolor","border","capture","cellpadding","cellspacing","checked","cite","class","clear","color","cols","colspan","command","commandfor","controls","controlslist","coords","crossorigin","datetime","decoding","default","dir","disabled","disablepictureinpicture","disableremoteplayback","download","draggable","enctype","enterkeyhint","exportparts","face","for","headers","height","hidden","high","href","hreflang","id","inert","inputmode","integrity","ismap","kind","label","lang","list","loading","loop","low","max","maxlength","media","method","min","minlength","multiple","muted","name","nonce","noshade","novalidate","nowrap","open","optimum","part","pattern","placeholder","playsinline","popover","popovertarget","popovertargetaction","poster","preload","pubdate","radiogroup","readonly","rel","required","rev","reversed","role","rows","rowspan","spellcheck","scope","selected","shape","size","sizes","slot","span","srclang","start","src","srcset","step","style","summary","tabindex","title","translate","type","usemap","valign","value","width","wrap","xmlns"]),q=l(["accent-height","accumulate","additive","alignment-baseline","amplitude","ascent","attributename","attributetype","azimuth","basefrequency","baseline-shift","begin","bias","by","class","clip","clippathunits","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","cx","cy","d","dx","dy","diffuseconstant","direction","display","divisor","dur","edgemode","elevation","end","exponent","fill","fill-opacity","fill-rule","filter","filterunits","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","fx","fy","g1","g2","glyph-name","glyphref","gradientunits","gradienttransform","height","href","id","image-rendering","in","in2","intercept","k","k1","k2","k3","k4","kerning","keypoints","keysplines","keytimes","lang","lengthadjust","letter-spacing","kernelmatrix","kernelunitlength","lighting-color","local","marker-end","marker-mid","marker-start","markerheight","markerunits","markerwidth","maskcontentunits","maskunits","max","mask","mask-type","media","method","mode","min","name","numoctaves","offset","operator","opacity","order","orient","orientation","origin","overflow","paint-order","path","pathlength","patterncontentunits","patterntransform","patternunits","points","preservealpha","preserveaspectratio","primitiveunits","r","rx","ry","radius","refx","refy","repeatcount","repeatdur","restart","result","rotate","scale","seed","shape-rendering","slope","specularconstant","specularexponent","spreadmethod","startoffset","stddeviation","stitchtiles","stop-color","stop-opacity","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke","stroke-width","style","surfacescale","systemlanguage","tabindex","tablevalues","targetx","targety","transform","transform-origin","text-anchor","text-decoration","text-rendering","textlength","type","u1","u2","unicode","values","viewbox","visibility","version","vert-adv-y","vert-origin-x","vert-origin-y","width","word-spacing","wrap","writing-mode","xchannelselector","ychannelselector","x","x1","x2","xmlns","y","y1","y2","z","zoomandpan"]),$=l(["accent","accentunder","align","bevelled","close","columnalign","columnlines","columnspacing","columnspan","denomalign","depth","dir","display","displaystyle","encoding","fence","frame","height","href","id","largeop","length","linethickness","lquote","lspace","mathbackground","mathcolor","mathsize","mathvariant","maxsize","minsize","movablelimits","notation","numalign","open","rowalign","rowlines","rowspacing","rowspan","rspace","rquote","scriptlevel","scriptminsize","scriptsizemultiplier","selection","separator","separators","stretchy","subscriptshift","supscriptshift","symmetric","voffset","width","xmlns"]),K=l(["xlink:href","xml:id","xlink:title","xml:space","xmlns:xlink"]),V=c(/{{[\w\W]*|^[\w\W]*}}/g),Z=c(/<%[\w\W]*|^[\w\W]*%>/g),J=c(/\${[\w\W]*/g),Q=c(/^data-[\-\w.\u00B7-\uFFFF]+$/),ee=c(/^aria-[\-\w]+$/),te=c(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),ne=c(/^(?:\w+script|data):/i),oe=c(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),re=c(/^html$/i),ie=c(/^[a-z][.\w]*(-[.\w]+)+$/i),ae=1,le=3,ce=7,se=8,ue=9,fe=11,me=function(){return"undefined"==typeof window?null:window};var pe=function e(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:me();const o=t=>e(t);if(o.version="3.4.6",o.removed=[],!t||!t.document||t.document.nodeType!==ue||!t.Element)return o.isSupported=!1,o;let r=t.document;const i=r,a=i.currentScript;t.DocumentFragment;const c=t.HTMLTemplateElement,u=t.Node,f=t.Element,m=t.NodeFilter,k=t.NamedNodeMap;void 0===k&&(t.NamedNodeMap||t.MozNamedAttrMap),t.HTMLFormElement;const L=t.DOMParser,z=t.trustedTypes,pe=f.prototype,de=P(pe,"cloneNode"),he=P(pe,"remove"),ge=P(pe,"nextSibling"),ye=P(pe,"childNodes"),Te=P(pe,"parentNode"),be=P(pe,"shadowRoot"),Ae=P(pe,"attributes"),Se=u&&u.prototype?P(u.prototype,"nodeType"):null,Ee=u&&u.prototype?P(u.prototype,"nodeName"):null;if("function"==typeof c){const e=r.createElement("template");e.content&&e.content.ownerDocument&&(r=e.content.ownerDocument)}let Ne,_e="";const Oe=r,De=Oe.implementation,Re=Oe.createNodeIterator,we=Oe.createDocumentFragment,Ie=Oe.getElementsByTagName,ve=i.importNode;let Ce={afterSanitizeAttributes:[],afterSanitizeElements:[],afterSanitizeShadowDOM:[],beforeSanitizeAttributes:[],beforeSanitizeElements:[],beforeSanitizeShadowDOM:[],uponSanitizeAttribute:[],uponSanitizeElement:[],uponSanitizeShadowNode:[]};o.isSupported="function"==typeof n&&"function"==typeof Te&&De&&void 0!==De.createHTMLDocument;const xe=V,ke=Z,Le=J,Me=Q,ze=ee,Fe=ne,Pe=oe,Ue=ie;let He=te,Be=null;const je=M({},[...U,...H,...B,...G,...Y]);let Ge=null;const We=M({},[...X,...q,...$,...K]);let Ye=Object.seal(s(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),Xe=null,qe=null;const $e=Object.seal(s(null,{tagCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeCheck:{writable:!0,configurable:!1,enumerable:!0,value:null}}));let Ke=!0,Ve=!0,Ze=!1,Je=!0,Qe=!1,et=!0,tt=!1,nt=!1,ot=!1,rt=!1,it=!1,at=!1,lt=!0,ct=!1;const st="user-content-";let ut=!0,ft=!1,mt={},pt=null;const dt=M({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let ht=null;const gt=M({},["audio","video","img","source","image","track"]);let yt=null;const Tt=M({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),bt="http://www.w3.org/1998/Math/MathML",At="http://www.w3.org/2000/svg",St="http://www.w3.org/1999/xhtml";let Et=St,Nt=!1,_t=null;const Ot=M({},[bt,At,St],A);let Dt=M({},["mi","mo","mn","ms","mtext"]),Rt=M({},["annotation-xml"]);const wt=M({},["title","style","font","a","script"]);let It=null;const vt=["application/xhtml+xml","text/html"];let Ct=null,xt=null;const kt=r.createElement("form"),Lt=function(e){return e instanceof RegExp||e instanceof Function},Mt=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(xt&&xt===e)return;e&&"object"==typeof e||(e={}),e=F(e),It=-1===vt.indexOf(e.PARSER_MEDIA_TYPE)?"text/html":e.PARSER_MEDIA_TYPE,Ct="application/xhtml+xml"===It?A:b,Be=I(e,"ALLOWED_TAGS")&&T(e.ALLOWED_TAGS)?M({},e.ALLOWED_TAGS,Ct):je,Ge=I(e,"ALLOWED_ATTR")&&T(e.ALLOWED_ATTR)?M({},e.ALLOWED_ATTR,Ct):We,_t=I(e,"ALLOWED_NAMESPACES")&&T(e.ALLOWED_NAMESPACES)?M({},e.ALLOWED_NAMESPACES,A):Ot,yt=I(e,"ADD_URI_SAFE_ATTR")&&T(e.ADD_URI_SAFE_ATTR)?M(F(Tt),e.ADD_URI_SAFE_ATTR,Ct):Tt,ht=I(e,"ADD_DATA_URI_TAGS")&&T(e.ADD_DATA_URI_TAGS)?M(F(gt),e.ADD_DATA_URI_TAGS,Ct):gt,pt=I(e,"FORBID_CONTENTS")&&T(e.FORBID_CONTENTS)?M({},e.FORBID_CONTENTS,Ct):dt,Xe=I(e,"FORBID_TAGS")&&T(e.FORBID_TAGS)?M({},e.FORBID_TAGS,Ct):F({}),qe=I(e,"FORBID_ATTR")&&T(e.FORBID_ATTR)?M({},e.FORBID_ATTR,Ct):F({}),mt=!!I(e,"USE_PROFILES")&&(e.USE_PROFILES&&"object"==typeof e.USE_PROFILES?F(e.USE_PROFILES):e.USE_PROFILES),Ke=!1!==e.ALLOW_ARIA_ATTR,Ve=!1!==e.ALLOW_DATA_ATTR,Ze=e.ALLOW_UNKNOWN_PROTOCOLS||!1,Je=!1!==e.ALLOW_SELF_CLOSE_IN_ATTR,Qe=e.SAFE_FOR_TEMPLATES||!1,et=!1!==e.SAFE_FOR_XML,tt=e.WHOLE_DOCUMENT||!1,rt=e.RETURN_DOM||!1,it=e.RETURN_DOM_FRAGMENT||!1,at=e.RETURN_TRUSTED_TYPE||!1,ot=e.FORCE_BODY||!1,lt=!1!==e.SANITIZE_DOM,ct=e.SANITIZE_NAMED_PROPS||!1,ut=!1!==e.KEEP_CONTENT,ft=e.IN_PLACE||!1,He=function(e){try{return C(e,""),!0}catch(e){return!1}}(e.ALLOWED_URI_REGEXP)?e.ALLOWED_URI_REGEXP:te,Et="string"==typeof e.NAMESPACE?e.NAMESPACE:St,Dt=I(e,"MATHML_TEXT_INTEGRATION_POINTS")&&e.MATHML_TEXT_INTEGRATION_POINTS&&"object"==typeof e.MATHML_TEXT_INTEGRATION_POINTS?F(e.MATHML_TEXT_INTEGRATION_POINTS):M({},["mi","mo","mn","ms","mtext"]),Rt=I(e,"HTML_INTEGRATION_POINTS")&&e.HTML_INTEGRATION_POINTS&&"object"==typeof e.HTML_INTEGRATION_POINTS?F(e.HTML_INTEGRATION_POINTS):M({},["annotation-xml"]);const t=I(e,"CUSTOM_ELEMENT_HANDLING")&&e.CUSTOM_ELEMENT_HANDLING&&"object"==typeof e.CUSTOM_ELEMENT_HANDLING?F(e.CUSTOM_ELEMENT_HANDLING):s(null);if(Ye=s(null),I(t,"tagNameCheck")&&Lt(t.tagNameCheck)&&(Ye.tagNameCheck=t.tagNameCheck),I(t,"attributeNameCheck")&&Lt(t.attributeNameCheck)&&(Ye.attributeNameCheck=t.attributeNameCheck),I(t,"allowCustomizedBuiltInElements")&&"boolean"==typeof t.allowCustomizedBuiltInElements&&(Ye.allowCustomizedBuiltInElements=t.allowCustomizedBuiltInElements),Qe&&(Ve=!1),it&&(rt=!0),mt&&(Be=M({},Y),Ge=s(null),!0===mt.html&&(M(Be,U),M(Ge,X)),!0===mt.svg&&(M(Be,H),M(Ge,q),M(Ge,K)),!0===mt.svgFilters&&(M(Be,B),M(Ge,q),M(Ge,K)),!0===mt.mathMl&&(M(Be,G),M(Ge,$),M(Ge,K))),$e.tagCheck=null,$e.attributeCheck=null,I(e,"ADD_TAGS")&&("function"==typeof e.ADD_TAGS?$e.tagCheck=e.ADD_TAGS:T(e.ADD_TAGS)&&(Be===je&&(Be=F(Be)),M(Be,e.ADD_TAGS,Ct))),I(e,"ADD_ATTR")&&("function"==typeof e.ADD_ATTR?$e.attributeCheck=e.ADD_ATTR:T(e.ADD_ATTR)&&(Ge===We&&(Ge=F(Ge)),M(Ge,e.ADD_ATTR,Ct))),I(e,"ADD_URI_SAFE_ATTR")&&T(e.ADD_URI_SAFE_ATTR)&&M(yt,e.ADD_URI_SAFE_ATTR,Ct),I(e,"FORBID_CONTENTS")&&T(e.FORBID_CONTENTS)&&(pt===dt&&(pt=F(pt)),M(pt,e.FORBID_CONTENTS,Ct)),I(e,"ADD_FORBID_CONTENTS")&&T(e.ADD_FORBID_CONTENTS)&&(pt===dt&&(pt=F(pt)),M(pt,e.ADD_FORBID_CONTENTS,Ct)),ut&&(Be["#text"]=!0),tt&&M(Be,["html","head","body"]),Be.table&&(M(Be,["tbody"]),delete Xe.tbody),e.TRUSTED_TYPES_POLICY){if("function"!=typeof e.TRUSTED_TYPES_POLICY.createHTML)throw x('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if("function"!=typeof e.TRUSTED_TYPES_POLICY.createScriptURL)throw x('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');Ne=e.TRUSTED_TYPES_POLICY,_e=Ne.createHTML("")}else void 0===Ne&&(Ne=function(e,t){if("object"!=typeof e||"function"!=typeof e.createPolicy)return null;let n=null;const o="data-tt-policy-suffix";t&&t.hasAttribute(o)&&(n=t.getAttribute(o));const r="dompurify"+(n?"#"+n:"");try{return e.createPolicy(r,{createHTML:e=>e,createScriptURL:e=>e})}catch(e){return console.warn("TrustedTypes policy "+r+" could not be created."),null}}(z,a)),null!==Ne&&"string"==typeof _e&&(_e=Ne.createHTML(""));l&&l(e),xt=e},zt=M({},[...H,...B,...j]),Ft=M({},[...G,...W]),Pt=function(e){g(o.removed,{element:e});try{Te(e).removeChild(e)}catch(t){he(e)}},Ut=function(e,t){try{g(o.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){g(o.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e)if(rt||it)try{Pt(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},Ht=function(e){let t=null,n=null;if(ot)e="<remove></remove>"+e;else{const t=S(e,/^[\r\n\t ]+/);n=t&&t[0]}"application/xhtml+xml"===It&&Et===St&&(e='<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>'+e+"</body></html>");const o=Ne?Ne.createHTML(e):e;if(Et===St)try{t=(new L).parseFromString(o,It)}catch(e){}if(!t||!t.documentElement){t=De.createDocument(Et,"template",null);try{t.documentElement.innerHTML=Nt?_e:o}catch(e){}}const i=t.body||t.documentElement;return e&&n&&i.insertBefore(r.createTextNode(n),i.childNodes[0]||null),Et===St?Ie.call(t,tt?"html":"body")[0]:tt?t.documentElement:i},Bt=function(e){return Re.call(e.ownerDocument||e,e,m.SHOW_ELEMENT|m.SHOW_COMMENT|m.SHOW_TEXT|m.SHOW_PROCESSING_INSTRUCTION|m.SHOW_CDATA_SECTION,null)},jt=function(e){e.normalize();const t=Re.call(e.ownerDocument||e,e,m.SHOW_TEXT|m.SHOW_COMMENT|m.SHOW_CDATA_SECTION|m.SHOW_PROCESSING_INSTRUCTION,null);let n=t.nextNode();for(;n;){let e=n.data;p([xe,ke,Le],t=>{e=E(e,t," ")}),n.data=e,n=t.nextNode()}},Gt=function(e){const t=Ee?Ee(e):null;return"string"==typeof t&&("form"===Ct(t)&&("string"!=typeof e.nodeName||"string"!=typeof e.textContent||"function"!=typeof e.removeChild||e.attributes!==Ae(e)||"function"!=typeof e.removeAttribute||"function"!=typeof e.setAttribute||"string"!=typeof e.namespaceURI||"function"!=typeof e.insertBefore||"function"!=typeof e.hasChildNodes||e.childNodes!==ye(e)))},Wt=function(e){if(!Se||"object"!=typeof e||null===e)return!1;try{return Se(e)===fe}catch(e){return!1}},Yt=function(e){if(!Se||"object"!=typeof e||null===e)return!1;try{return"number"==typeof Se(e)}catch(e){return!1}};function Xt(e,t,n){p(e,e=>{e.call(o,t,n,xt)})}const qt=function(e){let t=null;if(Xt(Ce.beforeSanitizeElements,e,null),Gt(e))return Pt(e),!0;const n=Ct(e.nodeName);if(Xt(Ce.uponSanitizeElement,e,{tagName:n,allowedTags:Be}),et&&e.hasChildNodes()&&!Yt(e.firstElementChild)&&C(/<[/\w!]/g,e.innerHTML)&&C(/<[/\w!]/g,e.textContent))return Pt(e),!0;if(et&&e.namespaceURI===St&&"style"===n&&Yt(e.firstElementChild))return Pt(e),!0;if(e.nodeType===ce)return Pt(e),!0;if(et&&e.nodeType===se&&C(/<[/\w]/g,e.data))return Pt(e),!0;if(Xe[n]||!($e.tagCheck instanceof Function&&$e.tagCheck(n))&&!Be[n]){if(!Xe[n]&&Vt(n)){if(Ye.tagNameCheck instanceof RegExp&&C(Ye.tagNameCheck,n))return!1;if(Ye.tagNameCheck instanceof Function&&Ye.tagNameCheck(n))return!1}if(ut&&!pt[n]){const t=Te(e)||e.parentNode,n=ye(e)||e.childNodes;if(n&&t){for(let o=n.length-1;o>=0;--o){const r=de(n[o],!0);t.insertBefore(r,ge(e))}}}return Pt(e),!0}return((Se?Se(e):e.nodeType)!==ae||function(e){let t=Te(e);t&&t.tagName||(t={namespaceURI:Et,tagName:"template"});const n=b(e.tagName),o=b(t.tagName);return!!_t[e.namespaceURI]&&(e.namespaceURI===At?t.namespaceURI===St?"svg"===n:t.namespaceURI===bt?"svg"===n&&("annotation-xml"===o||Dt[o]):Boolean(zt[n]):e.namespaceURI===bt?t.namespaceURI===St?"math"===n:t.namespaceURI===At?"math"===n&&Rt[o]:Boolean(Ft[n]):e.namespaceURI===St?!(t.namespaceURI===At&&!Rt[o])&&!(t.namespaceURI===bt&&!Dt[o])&&!Ft[n]&&(wt[n]||!zt[n]):!("application/xhtml+xml"!==It||!_t[e.namespaceURI]))}(e))&&("noscript"!==n&&"noembed"!==n&&"noframes"!==n||!C(/<\/no(script|embed|frames)/i,e.innerHTML))?(Qe&&e.nodeType===le&&(t=e.textContent,p([xe,ke,Le],e=>{t=E(t,e," ")}),e.textContent!==t&&(g(o.removed,{element:e.cloneNode()}),e.textContent=t)),Xt(Ce.afterSanitizeElements,e,null),!1):(Pt(e),!0)},$t=function(e,t,n){if(qe[t])return!1;if(lt&&("id"===t||"name"===t)&&(n in r||n in kt))return!1;const o=Ge[t]||$e.attributeCheck instanceof Function&&$e.attributeCheck(t,e);if(Ve&&!qe[t]&&C(Me,t));else if(Ke&&C(ze,t));else if(!o||qe[t]){if(!(Vt(e)&&(Ye.tagNameCheck instanceof RegExp&&C(Ye.tagNameCheck,e)||Ye.tagNameCheck instanceof Function&&Ye.tagNameCheck(e))&&(Ye.attributeNameCheck instanceof RegExp&&C(Ye.attributeNameCheck,t)||Ye.attributeNameCheck instanceof Function&&Ye.attributeNameCheck(t,e))||"is"===t&&Ye.allowCustomizedBuiltInElements&&(Ye.tagNameCheck instanceof RegExp&&C(Ye.tagNameCheck,n)||Ye.tagNameCheck instanceof Function&&Ye.tagNameCheck(n))))return!1}else if(yt[t]);else if(C(He,E(n,Pe,"")));else if("src"!==t&&"xlink:href"!==t&&"href"!==t||"script"===e||0!==N(n,"data:")||!ht[e]){if(Ze&&!C(Fe,E(n,Pe,"")));else if(n)return!1}else;return!0},Kt=M({},["annotation-xml","color-profile","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","missing-glyph"]),Vt=function(e){return!Kt[b(e)]&&C(Ue,e)},Zt=function(e){Xt(Ce.beforeSanitizeAttributes,e,null);const t=e.attributes;if(!t||Gt(e))return;const n={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:Ge,forceKeepAttr:void 0};let r=t.length;for(;r--;){const i=t[r],a=i.name,l=i.namespaceURI,c=i.value,s=Ct(a),u=c;let f="value"===a?u:_(u);if(n.attrName=s,n.attrValue=f,n.keepAttr=!0,n.forceKeepAttr=void 0,Xt(Ce.uponSanitizeAttribute,e,n),f=n.attrValue,!ct||"id"!==s&&"name"!==s||0===N(f,st)||(Ut(a,e),f=st+f),et&&C(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i,f)){Ut(a,e);continue}if("attributename"===s&&S(f,"href")){Ut(a,e);continue}if(n.forceKeepAttr)continue;if(!n.keepAttr){Ut(a,e);continue}if(!Je&&C(/\/>/i,f)){Ut(a,e);continue}Qe&&p([xe,ke,Le],e=>{f=E(f,e," ")});const m=Ct(e.nodeName);if($t(m,s,f)){if(Ne&&"object"==typeof z&&"function"==typeof z.getAttributeType)if(l);else switch(z.getAttributeType(m,s)){case"TrustedHTML":f=Ne.createHTML(f);break;case"TrustedScriptURL":f=Ne.createScriptURL(f)}if(f!==u)try{l?e.setAttributeNS(l,a,f):e.setAttribute(a,f),Gt(e)?Pt(e):h(o.removed)}catch(t){Ut(a,e)}}else Ut(a,e)}Xt(Ce.afterSanitizeAttributes,e,null)},Jt=function(e){let t=null;const n=Bt(e);for(Xt(Ce.beforeSanitizeShadowDOM,e,null);t=n.nextNode();)Xt(Ce.uponSanitizeShadowNode,t,null),qt(t),Zt(t),Wt(t.content)&&Jt(t.content);Xt(Ce.afterSanitizeShadowDOM,e,null)},Qt=function(e){if((Se?Se(e):e.nodeType)===ae){const t=be?be(e):e.shadowRoot;Wt(t)&&(Qt(t),Jt(t))}const t=ye?ye(e):e.childNodes;if(!t)return;const n=[];p(t,e=>{g(n,e)});for(const e of n)Qt(e)};return o.sanitize=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=null,r=null,a=null,l=null;if(Nt=!e,Nt&&(e="\x3c!--\x3e"),"string"!=typeof e&&!Yt(e)&&"string"!=typeof(e=function(e){switch(typeof e){case"string":return e;case"number":return O(e);case"boolean":return D(e);case"bigint":return R?R(e):"0";case"symbol":return w?w(e):"Symbol()";case"undefined":default:return v(e);case"function":case"object":{if(null===e)return v(e);const t=e,n=P(t,"toString");if("function"==typeof n){const e=n(t);return"string"==typeof e?e:v(e)}return v(e)}}}(e)))throw x("dirty is not a string, aborting");if(!o.isSupported)return e;if(nt||Mt(t),o.removed=[],"string"==typeof e&&(ft=!1),ft){const t=Ee?Ee(e):e.nodeName;if("string"==typeof t){const e=Ct(t);if(!Be[e]||Xe[e])throw x("root node is forbidden and cannot be sanitized in-place")}if(Gt(e))throw x("root node is clobbered and cannot be sanitized in-place");Qt(e)}else if(Yt(e))n=Ht("\x3c!----\x3e"),r=n.ownerDocument.importNode(e,!0),r.nodeType===ae&&"BODY"===r.nodeName||"HTML"===r.nodeName?n=r:n.appendChild(r),Qt(r);else{if(!rt&&!Qe&&!tt&&-1===e.indexOf("<"))return Ne&&at?Ne.createHTML(e):e;if(n=Ht(e),!n)return rt?null:at?_e:""}n&&ot&&Pt(n.firstChild);const c=Bt(ft?e:n);for(;a=c.nextNode();)qt(a),Zt(a),Wt(a.content)&&Jt(a.content);if(ft)return Qe&&jt(e),e;if(rt){if(Qe&&jt(n),it)for(l=we.call(n.ownerDocument);n.firstChild;)l.appendChild(n.firstChild);else l=n;return(Ge.shadowroot||Ge.shadowrootmode)&&(l=ve.call(i,l,!0)),l}let s=tt?n.outerHTML:n.innerHTML;return tt&&Be["!doctype"]&&n.ownerDocument&&n.ownerDocument.doctype&&n.ownerDocument.doctype.name&&C(re,n.ownerDocument.doctype.name)&&(s="<!DOCTYPE "+n.ownerDocument.doctype.name+">\n"+s),Qe&&p([xe,ke,Le],e=>{s=E(s,e," ")}),Ne&&at?Ne.createHTML(s):s},o.setConfig=function(){Mt(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),nt=!0},o.clearConfig=function(){xt=null,nt=!1},o.isValidAttribute=function(e,t,n){xt||Mt({});const o=Ct(e),r=Ct(t);return $t(o,r,n)},o.addHook=function(e,t){"function"==typeof t&&g(Ce[e],t)},o.removeHook=function(e,t){if(void 0!==t){const n=d(Ce[e],t);return-1===n?void 0:y(Ce[e],n,1)[0]}return h(Ce[e])},o.removeHooks=function(e){Ce[e]=[]},o.removeAllHooks=function(){Ce={afterSanitizeAttributes:[],afterSanitizeElements:[],afterSanitizeShadowDOM:[],beforeSanitizeAttributes:[],beforeSanitizeElements:[],beforeSanitizeShadowDOM:[],uponSanitizeAttribute:[],uponSanitizeElement:[],uponSanitizeShadowNode:[]}},o}();return pe}); //# sourceMappingURL=purify.min.js.map
dist/purify.min.js.map+1 −1 modified@@ -1 +1 @@ -{"version":3,"file":"purify.min.js","sources":["../src/utils.ts","../src/tags.ts","../src/attrs.ts","../src/regexp.ts","../src/purify.ts"],"sourcesContent":[null,null,null,null,null],"names":["entries","Object","setPrototypeOf","isFrozen","getPrototypeOf","getOwnPropertyDescriptor","freeze","seal","create","_ref","Reflect","apply","construct","x","func","thisArg","_len","arguments","length","args","Array","_key","Func","_len2","_key2","arrayForEach","unapply","prototype","forEach","arrayLastIndexOf","lastIndexOf","arrayPop","pop","arrayPush","push","arraySplice","splice","arrayIsArray","isArray","stringToLowerCase","String","toLowerCase","stringToString","toString","stringMatch","match","stringReplace","replace","stringIndexOf","indexOf","stringTrim","trim","numberToString","Number","booleanToString","Boolean","bigintToString","BigInt","symbolToString","Symbol","objectHasOwnProperty","hasOwnProperty","objectToString","regExpTest","RegExp","test","typeErrorCreate","TypeError","_len4","_key4","lastIndex","_len3","_key3","addToSet","set","array","transformCaseFunc","l","element","lcElement","cleanArray","index","clone","object","newObject","_ref2","_ref3","_slicedToArray","property","value","constructor","lookupGetter","prop","desc","get","html","svg","svgFilters","svgDisallowed","mathMl","mathMlDisallowed","text","xml","MUSTACHE_EXPR","ERB_EXPR","TMPLIT_EXPR","DATA_ATTR","ARIA_ATTR","IS_ALLOWED_URI","IS_SCRIPT_OR_DATA","ATTR_WHITESPACE","DOCTYPE_NAME","CUSTOM_ELEMENT","NODE_TYPE","getGlobal","window","purify","createDOMPurify","undefined","DOMPurify","root","version","VERSION","removed","document","nodeType","Element","isSupported","originalDocument","currentScript","DocumentFragment","HTMLTemplateElement","Node","NodeFilter","_window$NamedNodeMap","NamedNodeMap","MozNamedAttrMap","HTMLFormElement","DOMParser","trustedTypes","ElementPrototype","cloneNode","remove","getNextSibling","getChildNodes","getParentNode","getNodeType","template","createElement","content","ownerDocument","trustedTypesPolicy","emptyHTML","_document","implementation","createNodeIterator","createDocumentFragment","getElementsByTagName","importNode","hooks","afterSanitizeAttributes","afterSanitizeElements","afterSanitizeShadowDOM","beforeSanitizeAttributes","beforeSanitizeElements","beforeSanitizeShadowDOM","uponSanitizeAttribute","uponSanitizeElement","uponSanitizeShadowNode","createHTMLDocument","EXPRESSIONS","ALLOWED_TAGS","DEFAULT_ALLOWED_TAGS","TAGS","ALLOWED_ATTR","DEFAULT_ALLOWED_ATTR","ATTRS","CUSTOM_ELEMENT_HANDLING","tagNameCheck","writable","configurable","enumerable","attributeNameCheck","allowCustomizedBuiltInElements","FORBID_TAGS","FORBID_ATTR","EXTRA_ELEMENT_HANDLING","tagCheck","attributeCheck","ALLOW_ARIA_ATTR","ALLOW_DATA_ATTR","ALLOW_UNKNOWN_PROTOCOLS","ALLOW_SELF_CLOSE_IN_ATTR","SAFE_FOR_TEMPLATES","SAFE_FOR_XML","WHOLE_DOCUMENT","SET_CONFIG","FORCE_BODY","RETURN_DOM","RETURN_DOM_FRAGMENT","RETURN_TRUSTED_TYPE","SANITIZE_DOM","SANITIZE_NAMED_PROPS","SANITIZE_NAMED_PROPS_PREFIX","KEEP_CONTENT","IN_PLACE","USE_PROFILES","FORBID_CONTENTS","DEFAULT_FORBID_CONTENTS","DATA_URI_TAGS","DEFAULT_DATA_URI_TAGS","URI_SAFE_ATTRIBUTES","DEFAULT_URI_SAFE_ATTRIBUTES","MATHML_NAMESPACE","SVG_NAMESPACE","HTML_NAMESPACE","NAMESPACE","IS_EMPTY_INPUT","ALLOWED_NAMESPACES","DEFAULT_ALLOWED_NAMESPACES","MATHML_TEXT_INTEGRATION_POINTS","HTML_INTEGRATION_POINTS","COMMON_SVG_AND_HTML_ELEMENTS","PARSER_MEDIA_TYPE","SUPPORTED_PARSER_MEDIA_TYPES","CONFIG","formElement","isRegexOrFunction","testValue","Function","_parseConfig","cfg","ADD_URI_SAFE_ATTR","ADD_DATA_URI_TAGS","_unused","isRegex","ALLOWED_URI_REGEXP","customElementHandling","ADD_TAGS","ADD_ATTR","ADD_FORBID_CONTENTS","table","tbody","TRUSTED_TYPES_POLICY","createHTML","createScriptURL","purifyHostElement","createPolicy","suffix","ATTR_NAME","hasAttribute","getAttribute","policyName","scriptUrl","_","console","warn","_createTrustedTypesPolicy","ALL_SVG_TAGS","ALL_MATHML_TAGS","_forceRemove","node","removeChild","_removeAttribute","name","attribute","getAttributeNode","from","removeAttribute","setAttribute","_initDocument","dirty","doc","leadingWhitespace","matches","dirtyPayload","parseFromString","documentElement","createDocument","innerHTML","body","insertBefore","createTextNode","childNodes","call","_createNodeIterator","SHOW_ELEMENT","SHOW_COMMENT","SHOW_TEXT","SHOW_PROCESSING_INSTRUCTION","SHOW_CDATA_SECTION","_scrubTemplateExpressions","normalize","walker","currentNode","nextNode","data","expr","_isClobbered","nodeName","textContent","attributes","namespaceURI","hasChildNodes","_isNode","_executeHooks","hook","_sanitizeElements","tagName","allowedTags","firstElementChild","_isBasicCustomElement","parentNode","i","childClone","parent","parentTagName","_checkValidNamespace","_isValidAttribute","lcTag","lcName","nameIsPermitted","RESERVED_CUSTOM_ELEMENT_NAMES","_sanitizeAttributes","hookEvent","attrName","attrValue","keepAttr","allowedAttributes","forceKeepAttr","attr","initValue","getAttributeType","setAttributeNS","_sanitizeShadowDOM","fragment","shadowNode","shadowIterator","_sanitizeAttachedShadowRoots","shadowRoot","sr","snapshot","child","sanitize","importedNode","returnNode","valueAsRecord","valueToString","stringified","stringifyValue","nn","appendChild","firstChild","nodeIterator","shadowroot","shadowrootmode","serializedHTML","outerHTML","doctype","setConfig","clearConfig","isValidAttribute","tag","addHook","entryPoint","hookFunction","removeHook","removeHooks","removeAllHooks"],"mappings":"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AEjCA,GACiB,iBAAVA,GACPA,EAAMC,cAAgBzF,OAEtBmF,EAAUI,GAAYN,EAAMO,GAE5BL,EAAUI,GAAYC,EAG5B,CAEA,OAAOL,CACT,CAmEA,SAASO,EACPR,EACAS,GAEA,KAAkB,OAAXT,GAAiB,CACtB,MAAMU,EAAOxF,EAAyB8E,EAAQS,GAE9C,GAAIC,EAAM,CACR,GAAIA,EAAKC,IACP,OAAOpE,EAAQmE,EAAKC,KAGtB,GAA0B,mBAAfD,EAAKJ,MACd,OAAO/D,EAAQmE,EAAKJ,MAExB,CAEAN,EAAS/E,EAAe+E,EAC1B,CAMA,OAJA,WACE,OAAO,IACT,CAGF,CC1RO,MAAMY,EAAOzF,EAAO,CACzB,IACA,OACA,UACA,UACA,OACA,UACA,QACA,QACA,IACA,MACA,MACA,MACA,QACA,aACA,OACA,KACA,SACA,SACA,UACA,SACA,OACA,OACA,MACA,WACA,UACA,OACA,WACA,KACA,YACA,MACA,UACA,MACA,SACA,MACA,MACA,KACA,KACA,UACA,KACA,WACA,aACA,SACA,OACA,SACA,OACA,KACA,KACA,KACA,KACA,KACA,KACA,OACA,SACA,SACA,KACA,OACA,IACA,MACA,QACA,MACA,MACA,QACA,SACA,KACA,OACA,MACA,OACA,UACA,OACA,WACA,QACA,MACA,OACA,KACA,WACA,SACA,SACA,IACA,UACA,MACA,WACA,IACA,KACA,KACA,OACA,IACA,OACA,SACA,UACA,SACA,SACA,OACA,QACA,SACA,SACA,OACA,SACA,SACA,QACA,MACA,UACA,MACA,QACA,QACA,KACA,WACA,WACA,QACA,KACA,QACA,OACA,KACA,QACA,KACA,IACA,KACA,MACA,QACA,QAGW0F,EAAM1F,EAAO,CACxB,MACA,IACA,WACA,cACA,eACA,eACA,gBACA,mBACA,SACA,WACA,OACA,OACA,UACA,eACA,cACA,SACA,OACA,IACA,QACA,WACA,QACA,QACA,YACA,OACA,iBACA,SACA,OACA,WACA,QACA,OACA,OACA,UACA,UACA,WACA,iBACA,OACA,OACA,QACA,SACA,SACA,OACA,WACA,QACA,OACA,QACA,OACA,UAGW2F,EAAa3F,EAAO,CAC/B,UACA,gBACA,sBACA,cACA,mBACA,oBACA,oBACA,iBACA,eACA,UACA,UACA,UACA,UACA,UACA,iBACA,UACA,UACA,cACA,eACA,WACA,eACA,qBACA,cACA,SACA,iBAOW4F,EAAgB5F,EAAO,CAClC,UACA,gBACA,SACA,UACA,YACA,mBACA,iBACA,gBACA,gBACA,gBACA,QACA,YACA,OACA,eACA,YACA,UACA,gBACA,SACA,MACA,aACA,UACA,QAGW6F,EAAS7F,EAAO,CAC3B,OACA,WACA,SACA,UACA,QACA,SACA,KACA,aACA,gBACA,KACA,KACA,QACA,UACA,WACA,QACA,OACA,KACA,SACA,QACA,SACA,OACA,OACA,UACA,SACA,MACA,QACA,MACA,SACA,aACA,gBAKW8F,EAAmB9F,EAAO,CACrC,UACA,cACA,aACA,WACA,YACA,UACA,UACA,SACA,SACA,QACA,YACA,aACA,iBACA,cACA,SAGW+F,EAAO/F,EAAO,CAAC,UC1RfyF,EAAOzF,EAAO,CACzB,SACA,SACA,QACA,MACA,iBACA,eACA,uBACA,WACA,aACA,UACA,SACA,UACA,cACA,cACA,UACA,OACA,QACA,QACA,QACA,OACA,UACA,UACA,aACA,WACA,eACA,SACA,cACA,WACA,WACA,UACA,MACA,WACA,0BACA,wBACA,WACA,YACA,UACA,eACA,cACA,OACA,MACA,UACA,SACA,SACA,OACA,OACA,WACA,KACA,QACA,YACA,YACA,QACA,OACA,QACA,OACA,OACA,UACA,OACA,MACA,MACA,YACA,QACA,SACA,MACA,YACA,WACA,QACA,OACA,QACA,UACA,aACA,SACA,OACA,UACA,OACA,UACA,cACA,cACA,UACA,gBACA,sBACA,SACA,UACA,UACA,aACA,WACA,MACA,WACA,MACA,WACA,OACA,OACA,UACA,aACA,QACA,WACA,QACA,OACA,QACA,OACA,OACA,UACA,QACA,MACA,SACA,OACA,QACA,UACA,WACA,QACA,YACA,OACA,SACA,SACA,QACA,QACA,OACA,UAGW0F,EAAM1F,EAAO,CACxB,gBACA,aACA,WACA,qBACA,YACA,SACA,gBACA,gBACA,UACA,gBACA,iBACA,QACA,OACA,KACA,QACA,OACA,gBACA,YACA,YACA,QACA,sBACA,8BACA,gBACA,kBACA,KACA,KACA,IACA,KACA,KACA,kBACA,YACA,UACA,UACA,MACA,WACA,YACA,MACA,WACA,OACA,eACA,YACA,SACA,cACA,cACA,gBACA,cACA,YACA,mBACA,eACA,aACA,eACA,cACA,KACA,KACA,KACA,KACA,aACA,WACA,gBACA,oBACA,SACA,OACA,KACA,kBACA,KACA,MACA,YACA,IACA,KACA,KACA,KACA,KACA,UACA,YACA,aACA,WACA,OACA,eACA,iBACA,eACA,mBACA,iBACA,QACA,aACA,aACA,eACA,eACA,cACA,cACA,mBACA,YACA,MACA,OACA,YACA,QACA,SACA,OACA,MACA,OACA,aACA,SACA,WACA,UACA,QACA,SACA,cACA,SACA,WACA,cACA,OACA,aACA,sBACA,mBACA,eACA,SACA,gBACA,sBACA,iBACA,IACA,KACA,KACA,SACA,OACA,OACA,cACA,YACA,UACA,SACA,SACA,QACA,OACA,kBACA,QACA,mBACA,mBACA,eACA,cACA,eACA,cACA,aACA,eACA,mBACA,oBACA,iBACA,kBACA,oBACA,iBACA,SACA,eACA,QACA,eACA,iBACA,WACA,cACA,UACA,UACA,YACA,mBACA,cACA,kBACA,iBACA,aACA,OACA,KACA,KACA,UACA,SACA,UACA,aACA,UACA,aACA,gBACA,gBACA,QACA,eACA,OACA,eACA,mBACA,mBACA,IACA,KACA,KACA,QACA,IACA,KACA,KACA,IACA,eAGW6F,EAAS7F,EAAO,CAC3B,SACA,cACA,QACA,WACA,QACA,cACA,cACA,gBACA,aACA,aACA,QACA,MACA,UACA,eACA,WACA,QACA,QACA,SACA,OACA,KACA,UACA,SACA,gBACA,SACA,SACA,iBACA,Y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"} \ No newline at end of file +{"version":3,"file":"purify.min.js","sources":["../src/utils.ts","../src/tags.ts","../src/attrs.ts","../src/regexp.ts","../src/purify.ts"],"sourcesContent":[null,null,null,null,null],"names":["entries","Object","setPrototypeOf","isFrozen","getPrototypeOf","getOwnPropertyDescriptor","freeze","seal","create","_ref","Reflect","apply","construct","x","func","thisArg","_len","arguments","length","args","Array","_key","Func","_len2","_key2","arrayForEach","unapply","prototype","forEach","arrayLastIndexOf","lastIndexOf","arrayPop","pop","arrayPush","push","arraySplice","splice","arrayIsArray","isArray","stringToLowerCase","String","toLowerCase","stringToString","toString","stringMatch","match","stringReplace","replace","stringIndexOf","indexOf","stringTrim","trim","numberToString","Number","booleanToString","Boolean","bigintToString","BigInt","symbolToString","Symbol","objectHasOwnProperty","hasOwnProperty","objectToString","regExpTest","RegExp","test","typeErrorCreate","TypeError","_len4","_key4","lastIndex","_len3","_key3","addToSet","set","array","transformCaseFunc","l","element","lcElement","cleanArray","index","clone","object","newObject","_ref2","_ref3","_slicedToArray","property","value","constructor","lookupGetter","prop","desc","get","html","svg","svgFilters","svgDisallowed","mathMl","mathMlDisallowed","text","xml","MUSTACHE_EXPR","ERB_EXPR","TMPLIT_EXPR","DATA_ATTR","ARIA_ATTR","IS_ALLOWED_URI","IS_SCRIPT_OR_DATA","ATTR_WHITESPACE","DOCTYPE_NAME","CUSTOM_ELEMENT","NODE_TYPE","getGlobal","window","purify","createDOMPurify","undefined","DOMPurify","root","version","VERSION","removed","document","nodeType","Element","isSupported","originalDocument","currentScript","DocumentFragment","HTMLTemplateElement","Node","NodeFilter","_window$NamedNodeMap","NamedNodeMap","MozNamedAttrMap","HTMLFormElement","DOMParser","trustedTypes","ElementPrototype","cloneNode","remove","getNextSibling","getChildNodes","getParentNode","getShadowRoot","getAttributes","getNodeType","getNodeName","template","createElement","content","ownerDocument","trustedTypesPolicy","emptyHTML","_document","implementation","createNodeIterator","createDocumentFragment","getElementsByTagName","importNode","hooks","afterSanitizeAttributes","afterSanitizeElements","afterSanitizeShadowDOM","beforeSanitizeAttributes","beforeSanitizeElements","beforeSanitizeShadowDOM","uponSanitizeAttribute","uponSanitizeElement","uponSanitizeShadowNode","createHTMLDocument","EXPRESSIONS","ALLOWED_TAGS","DEFAULT_ALLOWED_TAGS","TAGS","ALLOWED_ATTR","DEFAULT_ALLOWED_ATTR","ATTRS","CUSTOM_ELEMENT_HANDLING","tagNameCheck","writable","configurable","enumerable","attributeNameCheck","allowCustomizedBuiltInElements","FORBID_TAGS","FORBID_ATTR","EXTRA_ELEMENT_HANDLING","tagCheck","attributeCheck","ALLOW_ARIA_ATTR","ALLOW_DATA_ATTR","ALLOW_UNKNOWN_PROTOCOLS","ALLOW_SELF_CLOSE_IN_ATTR","SAFE_FOR_TEMPLATES","SAFE_FOR_XML","WHOLE_DOCUMENT","SET_CONFIG","FORCE_BODY","RETURN_DOM","RETURN_DOM_FRAGMENT","RETURN_TRUSTED_TYPE","SANITIZE_DOM","SANITIZE_NAMED_PROPS","SANITIZE_NAMED_PROPS_PREFIX","KEEP_CONTENT","IN_PLACE","USE_PROFILES","FORBID_CONTENTS","DEFAULT_FORBID_CONTENTS","DATA_URI_TAGS","DEFAULT_DATA_URI_TAGS","URI_SAFE_ATTRIBUTES","DEFAULT_URI_SAFE_ATTRIBUTES","MATHML_NAMESPACE","SVG_NAMESPACE","HTML_NAMESPACE","NAMESPACE","IS_EMPTY_INPUT","ALLOWED_NAMESPACES","DEFAULT_ALLOWED_NAMESPACES","MATHML_TEXT_INTEGRATION_POINTS","HTML_INTEGRATION_POINTS","COMMON_SVG_AND_HTML_ELEMENTS","PARSER_MEDIA_TYPE","SUPPORTED_PARSER_MEDIA_TYPES","CONFIG","formElement","isRegexOrFunction","testValue","Function","_parseConfig","cfg","ADD_URI_SAFE_ATTR","ADD_DATA_URI_TAGS","_unused","isRegex","ALLOWED_URI_REGEXP","customElementHandling","ADD_TAGS","ADD_ATTR","ADD_FORBID_CONTENTS","table","tbody","TRUSTED_TYPES_POLICY","createHTML","createScriptURL","purifyHostElement","createPolicy","suffix","ATTR_NAME","hasAttribute","getAttribute","policyName","scriptUrl","_","console","warn","_createTrustedTypesPolicy","ALL_SVG_TAGS","ALL_MATHML_TAGS","_forceRemove","node","removeChild","_removeAttribute","name","attribute","getAttributeNode","from","removeAttribute","setAttribute","_initDocument","dirty","doc","leadingWhitespace","matches","dirtyPayload","parseFromString","documentElement","createDocument","innerHTML","body","insertBefore","createTextNode","childNodes","call","_createNodeIterator","SHOW_ELEMENT","SHOW_COMMENT","SHOW_TEXT","SHOW_PROCESSING_INSTRUCTION","SHOW_CDATA_SECTION","_scrubTemplateExpressions","normalize","walker","currentNode","nextNode","data","expr","_isClobbered","realTagName","nodeName","textContent","attributes","namespaceURI","hasChildNodes","_isDocumentFragment","_isNode","_executeHooks","hook","_sanitizeElements","tagName","allowedTags","firstElementChild","_isBasicCustomElement","parentNode","i","childClone","parent","parentTagName","_checkValidNamespace","_isValidAttribute","lcTag","lcName","nameIsPermitted","RESERVED_CUSTOM_ELEMENT_NAMES","_sanitizeAttributes","hookEvent","attrName","attrValue","keepAttr","allowedAttributes","forceKeepAttr","attr","initValue","getAttributeType","setAttributeNS","_sanitizeShadowDOM","fragment","shadowNode","shadowIterator","_sanitizeAttachedShadowRoots","sr","shadowRoot","snapshot","child","sanitize","importedNode","returnNode","valueAsRecord","valueToString","stringified","stringifyValue","nn","appendChild","firstChild","nodeIterator","shadowroot","shadowrootmode","serializedHTML","outerHTML","doctype","setConfig","clearConfig","isValidAttribute","tag","addHook","entryPoint","hookFunction","removeHook","removeHooks","removeAllHooks"],"mappings":"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AEjCA,GACiB,iBAAVA,GACPA,EAAMC,cAAgBzF,OAEtBmF,EAAUI,GAAYN,EAAMO,GAE5BL,EAAUI,GAAYC,EAG5B,CAEA,OAAOL,CACT,CAmEA,SAASO,EACPR,EACAS,GAEA,KAAkB,OAAXT,GAAiB,CACtB,MAAMU,EAAOxF,EAAyB8E,EAAQS,GAE9C,GAAIC,EAAM,CACR,GAAIA,EAAKC,IACP,OAAOpE,EAAQmE,EAAKC,KAGtB,GAA0B,mBAAfD,EAAKJ,MACd,OAAO/D,EAAQmE,EAAKJ,MAExB,CAEAN,EAAS/E,EAAe+E,EAC1B,CAMA,OAJA,WACE,OAAO,IACT,CAGF,CC1RO,MAAMY,EAAOzF,EAAO,CACzB,IACA,OACA,UACA,UACA,OACA,UACA,QACA,QACA,IACA,MACA,MACA,MACA,QACA,aACA,OACA,KACA,SACA,SACA,UACA,SACA,OACA,OACA,MACA,WACA,UACA,OACA,WACA,KACA,YACA,MACA,UACA,MACA,SACA,MACA,MACA,KACA,KACA,UACA,KACA,WACA,aACA,SACA,OACA,SACA,OACA,KACA,KACA,KACA,KACA,KACA,KACA,OACA,SACA,SACA,KACA,OACA,IACA,MACA,QACA,MACA,MACA,QACA,SACA,KACA,OACA,MACA,OACA,UACA,OACA,WACA,QACA,MACA,OACA,KACA,WACA,SACA,SACA,IACA,UACA,MACA,WACA,IACA,KACA,KACA,OACA,IACA,OACA,SACA,UACA,SACA,SACA,OACA,QACA,SACA,SACA,OACA,SACA,SACA,QACA,MACA,UACA,MACA,QACA,QACA,KACA,WACA,WACA,QACA,KACA,QACA,OACA,KACA,QACA,KACA,IACA,KACA,MACA,QACA,QAGW0F,EAAM1F,EAAO,CACxB,MACA,IACA,WACA,cACA,eACA,eACA,gBACA,mBACA,SACA,WACA,OACA,OACA,UACA,eACA,cACA,SACA,OACA,IACA,QACA,WACA,QACA,QACA,YACA,OACA,iBACA,SACA,OACA,WACA,QACA,OACA,OACA,UACA,UACA,WACA,iBACA,OACA,OACA,QACA,SACA,SACA,OACA,WACA,QACA,OACA,QACA,OACA,UAGW2F,EAAa3F,EAAO,CAC/B,UACA,gBACA,sBACA,cACA,mBACA,oBACA,oBACA,iBACA,eACA,UACA,UACA,UACA,UACA,UACA,iBACA,UACA,UACA,cACA,eACA,WACA,eACA,qBACA,cACA,SACA,iBAOW4F,EAAgB5F,EAAO,CAClC,UACA,gBACA,SACA,UACA,YACA,mBACA,iBACA,gBACA,gBACA,gBACA,QACA,YACA,OACA,eACA,YACA,UACA,gBACA,SACA,MACA,aACA,UACA,QAGW6F,EAAS7F,EAAO,CAC3B,OACA,WACA,SACA,UACA,QACA,SACA,KACA,aACA,gBACA,KACA,KACA,QACA,UACA,WACA,QACA,OACA,KACA,SACA,QACA,SACA,OACA,OACA,UACA,SACA,MACA,QACA,MACA,SACA,aACA,gBAKW8F,EAAmB9F,EAAO,CACrC,UACA,cACA,aACA,WACA,YACA,UACA,UACA,SACA,SACA,QACA,YACA,aACA,iBACA,cACA,SAGW+F,EAAO/F,EAAO,CAAC,UC1RfyF,EAAOzF,EAAO,CACzB,SACA,SACA,QACA,MACA,iBACA,eACA,uBACA,WACA,aACA,UACA,SACA,UACA,cACA,cACA,UACA,OACA,QACA,QACA,QACA,OACA,UACA,UACA,aACA,WACA,eACA,SACA,cACA,WACA,WACA,UACA,MACA,WACA,0BACA,wBACA,WACA,YACA,UACA,eACA,cACA,OACA,MACA,UACA,SACA,SACA,OACA,OACA,WACA,KACA,QACA,YACA,YACA,QACA,OACA,QACA,OACA,OACA,UACA,OACA,MACA,MACA,YACA,QACA,SACA,MACA,YACA,WACA,QACA,OACA,QACA,UACA,aACA,SACA,OACA,UACA,OACA,UACA,cACA,cACA,UACA,gBACA,sBACA,SACA,UACA,UACA,aACA,WACA,MACA,WACA,MACA,WACA,OACA,OACA,UACA,aACA,QACA,WACA,QACA,OACA,QACA,OACA,OACA,UACA,QACA,MACA,SACA,OACA,QACA,UACA,WACA,QACA,YACA,OACA,SACA,SACA,QACA,QACA,OACA,UAGW0F,EAAM1F,EAAO,CACxB,gBACA,aACA,WACA,qBACA,YACA,SACA,gBACA,gBACA,UACA,gBACA,iBACA,QACA,OACA,KACA,QACA,OACA,gBACA,YACA,YACA,QACA,sBACA,8BACA,gBACA,kBACA,KACA,KACA,IACA,KACA,KACA,kBACA,YACA,UACA,UACA,MACA,WACA,YACA,MACA,WACA,OACA,eACA,YACA,SACA,cACA,cACA,gBACA,cACA,YACA,mBACA,eACA,aACA,eACA,cACA,KACA,KACA,KACA,KACA,aACA,WACA,gBACA,oBACA,SACA,OACA,KACA,kBACA,KACA,MACA,YACA,IACA,KACA,KACA,KACA,KACA,UACA,YACA,aACA,WACA,OACA,eACA,iBACA,eACA,mBACA,iBACA,QACA,aACA,aACA,eACA,eACA,cACA,cACA,mBACA,YACA,MACA,OACA,YACA,QACA,SACA,OACA,MACA,OACA,aACA,SACA,WACA,UACA,QACA,SACA,cACA,SACA,WACA,cACA,OACA,aACA,sBACA,mBACA,eACA,SACA,gBACA,sBACA,iBACA,IACA,KACA,KACA,SACA,OACA,OACA,cACA,YACA,UACA,SACA,SACA,QACA,OACA,kBACA,QACA,mBACA,mBACA,eACA,cACA,eACA,cACA,aACA,eACA,mBACA,oBACA,iBACA,kBACA,oBACA,iBACA,SACA,eACA,QACA,eACA,iBACA,WACA,cACA,UACA,UACA,YACA,mBACA,cACA,kBACA,iBACA,aACA,OACA,KACA,KACA,UACA,SACA,UACA,aACA,UACA,aACA,gBACA,gBACA,QACA,eACA,OACA,eACA,mBACA,mBACA,IACA,KACA,KACA,QACA,IACA,KACA,KACA,IACA,eAGW6F,EAAS7F,EAAO,CAC3B,SACA,cACA,QACA,WACA,QACA,cACA,cACA,gBACA,aACA,aACA,QACA,MACA,UACA,eACA,WACA,QACA,QACA,SACA,OACA,KACA,UACA,SACA,gBACA,SACA,SACA,iBACA,Y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"} \ No newline at end of file
git+0 −0 added.github/workflows/build-and-test.yml+2 −2 modified@@ -83,7 +83,7 @@ jobs: steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 + uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 with: egress-policy: audit @@ -157,7 +157,7 @@ jobs: steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 + uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 with: egress-policy: audit
.github/workflows/codeql-analysis.yml+4 −4 modified@@ -35,7 +35,7 @@ jobs: steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 + uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 with: egress-policy: audit @@ -50,14 +50,14 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 + uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 with: languages: ${{ matrix.language }} # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 + uses: github/codeql-action/autobuild@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -71,4 +71,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 + uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0
.github/workflows/dependency-review.yml+1 −1 modified@@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 + uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 with: egress-policy: audit
.github/workflows/fuzz.yml+1 −1 modified@@ -20,7 +20,7 @@ jobs: node-version: [20.x, 24.x, 26.x] steps: - name: Harden the runner - uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 + uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 with: egress-policy: audit
.github/workflows/scorecard.yml+2 −2 modified@@ -33,7 +33,7 @@ jobs: steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 + uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 with: egress-policy: audit @@ -77,6 +77,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 + uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 with: sarif_file: results.sarif
.github/workflows/sign-release.yml+1 −1 modified@@ -13,7 +13,7 @@ jobs: contents: write # to attach .sigstore bundles to the release id-token: write # OIDC for keyless signing steps: - - uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 + - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 with: egress-policy: audit - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
.github/workflows/slsa-provenance.yml+1 −1 modified@@ -14,7 +14,7 @@ jobs: id-token: write attestations: write steps: - - uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 + - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 with: egress-policy: audit - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
osv-scanner.toml+5 −0 modified@@ -38,3 +38,8 @@ reason = "Current package-lock includes vulnerable picomatch versions via develo id = "GHSA-c2qf-rxjj-qqgw" ignoreUntil = 2027-05-31 reason = "Current package-lock includes semver 7.5.0 via development tooling only; not part of the distributed runtime artifact." + +[[IgnoredVulns]] +id = "GHSA-jxxr-4gwj-5jf2" +reason = "brace-expansion DoS via large numeric ranges; low relevance unless user-controlled brace patterns are expanded. Prefer upgrading to brace-expansion 5.0.6." +ignoreUntil = 2027-05-31
package.json+2 −2 modified@@ -116,7 +116,7 @@ "@rollup/plugin-terser": "^1.0.0", "@rollup/plugin-typescript": "^12.3.0", "@types/estree": "^1.0.9", - "@types/node": "^25.8.0", + "@types/node": "^25.9.1", "cross-env": "^10.1.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.2.1", @@ -139,7 +139,7 @@ }, "name": "dompurify", "description": "DOMPurify is a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG. It's written in JavaScript and works in all modern browsers (Safari, Opera (15+), Internet Explorer (10+), Firefox and Chrome - as well as almost anything else using Blink or WebKit). DOMPurify is written by security people who have vast background in web attacks and XSS. Fear not.", - "version": "3.4.5", + "version": "3.4.6", "directories": { "test": "test" },
package-lock.json+6 −6 modified@@ -1,12 +1,12 @@ { "name": "dompurify", - "version": "3.4.5", + "version": "3.4.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "dompurify", - "version": "3.4.5", + "version": "3.4.6", "license": "(MPL-2.0 OR Apache-2.0)", "devDependencies": { "@babel/core": "^7.17.8", @@ -18,7 +18,7 @@ "@rollup/plugin-terser": "^1.0.0", "@rollup/plugin-typescript": "^12.3.0", "@types/estree": "^1.0.9", - "@types/node": "^25.8.0", + "@types/node": "^25.9.1", "cross-env": "^10.1.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.2.1", @@ -2648,9 +2648,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.8.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.8.0.tgz", - "integrity": "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==", + "version": "25.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", + "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", "dev": true, "license": "MIT", "dependencies": {
README.md+1 −1 modified@@ -6,7 +6,7 @@ DOMPurify is a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG. -It's also very simple to use and get started with. DOMPurify was [started in February 2014](https://github.com/cure53/DOMPurify/commit/a630922616927373485e0e787ab19e73e3691b2b) and, meanwhile, has reached version **v3.4.5**. +It's also very simple to use and get started with. DOMPurify was [started in February 2014](https://github.com/cure53/DOMPurify/commit/a630922616927373485e0e787ab19e73e3691b2b) and, meanwhile, has reached version **v3.4.6**. DOMPurify runs as JavaScript and works in all modern browsers (Safari (10+), Opera (15+), Edge, Firefox and Chrome - as well as almost anything else using Blink, Gecko or WebKit). It doesn't break on MSIE or other legacy browsers. It simply does nothing.
src/purify.ts+183 −29 modified@@ -166,8 +166,12 @@ function createDOMPurify(window: WindowLike = getGlobal()): DOMPurify { const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling'); const getChildNodes = lookupGetter(ElementPrototype, 'childNodes'); const getParentNode = lookupGetter(ElementPrototype, 'parentNode'); + const getShadowRoot = lookupGetter(ElementPrototype, 'shadowRoot'); + const getAttributes = lookupGetter(ElementPrototype, 'attributes'); const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeType') : null; + const getNodeName = + Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeName') : null; // As per issue #47, the web-components registry is inherited by a // new document created via createHTMLDocument. As per the spec @@ -1111,24 +1115,115 @@ function createDOMPurify(window: WindowLike = getGlobal()): DOMPurify { /** * _isClobbered * + * Detect DOM-clobbering on HTMLFormElement nodes. Form is the only HTML + * interface with [LegacyOverrideBuiltIns]; a descendant element with a + * `name` attribute matching a prototype property shadows that property + * on direct reads. We use this check at the IN_PLACE entry-point and + * during attribute sanitization to refuse clobbered forms. + * + * Realm safety (GHSA-hpcv-96wg-7vj8): every check in this function must + * work for foreign-realm forms — e.g. a <form> created inside a same- + * origin iframe and then handed to a parent-realm DOMPurify instance + * with IN_PLACE: true. The original implementation used + * `element instanceof HTMLFormElement` and `element.attributes + * instanceof NamedNodeMap`, both of which are realm-bound: a foreign- + * realm form is an instance of the *foreign* realm's HTMLFormElement, + * not the parent realm's. The instanceof short-circuited to false and + * the function returned false (= not clobbered) regardless of how + * thoroughly the form was clobbered. Sanitize then walked a clobbered + * .attributes and missed every attribute on the form root, leaving + * onmouseover / onclick / formaction / etc. intact. + * + * The realm-independent replacements: + * - HTMLFormElement detection — read the tag name through the cached + * Node.prototype.nodeName getter. WebIDL getters operate on internal + * slots that exist on every real Node regardless of which realm + * minted the JS wrapper, so getNodeName(foreignForm) === "FORM". + * - NamedNodeMap detection — compare the direct .attributes read + * against the cached Element.prototype.attributes getter. Same + * equality-probe pattern we use for .childNodes: if a clobbering + * child shadows the named property, the two reads diverge; if not, + * both return the same NamedNodeMap (same-realm OR foreign-realm — + * doesn't matter, both are the canonical attributes object for the + * node). + * * @param element element to check for clobbering attacks * @return true if clobbered, false if safe */ const _isClobbered = function (element: Element): boolean { + // Realm-independent tag-name probe. If we can't determine the tag + // name at all, we can't reason about clobbering — return false + // (the caller's other defences still apply). + const realTagName = getNodeName ? getNodeName(element) : null; + if (typeof realTagName !== 'string') { + return false; + } + + if (transformCaseFunc(realTagName) !== 'form') { + return false; + } + return ( - element instanceof HTMLFormElement && - (typeof element.nodeName !== 'string' || - typeof element.textContent !== 'string' || - typeof element.removeChild !== 'function' || - !(element.attributes instanceof NamedNodeMap) || - typeof element.removeAttribute !== 'function' || - typeof element.setAttribute !== 'function' || - typeof element.namespaceURI !== 'string' || - typeof element.insertBefore !== 'function' || - typeof element.hasChildNodes !== 'function') + typeof element.nodeName !== 'string' || + typeof element.textContent !== 'string' || + typeof element.removeChild !== 'function' || + // Realm-safe NamedNodeMap detection: equality against the cached + // prototype getter. Clobbered .attributes (e.g. <input name="attributes">) + // makes the direct read diverge from the cached read; a clean form + // (same-realm OR foreign-realm) has both reads pointing at the same + // canonical NamedNodeMap. + element.attributes !== getAttributes(element) || + typeof element.removeAttribute !== 'function' || + typeof element.setAttribute !== 'function' || + typeof element.namespaceURI !== 'string' || + typeof element.insertBefore !== 'function' || + typeof element.hasChildNodes !== 'function' || + // HTMLFormElement has [LegacyOverrideBuiltIns]: a descendant named + // "childNodes" shadows the prototype getter. Direct reads of + // form.childNodes from a clobbered form return the named child + // instead of the real NodeList, so any walk that reads it directly + // skips the form's real children. Compare the direct read to the + // cached Node.prototype getter — when the form's named-property + // getter intercepts the read, the two values differ and we flag + // the form. This catches every clobbering child type (input, + // select, etc.) regardless of whether the named child happens to + // carry a numeric .length, which a typeof-based probe would miss + // (e.g. HTMLSelectElement.length is a defined unsigned-long). + element.childNodes !== getChildNodes(element) ); }; + /** + * Checks whether the given value is a DocumentFragment from any realm. + * + * Realm safety (GHSA-hpcv-96wg-7vj8): the original sites used + * `value instanceof DocumentFragment`, which is realm-bound — a fragment + * from a foreign realm (template content or shadow root from an iframe + * document) is an instance of the foreign realm's DocumentFragment, not + * the parent realm's, so the check returned false and the template- + * content / shadow-root recursion was silently skipped. The attacker + * payload inside survived untouched. + * + * The realm-independent replacement reads `nodeType` through the cached + * Node.prototype getter and compares to the DOCUMENT_FRAGMENT_NODE + * constant (11). nodeType is a numeric value resolved from the node's + * internal slot, identical across realms for the same kind of node. + * + * @param value object to check + * @return true if value is a DocumentFragment-shaped node from any realm + */ + const _isDocumentFragment = function (value: unknown): boolean { + if (!getNodeType || typeof value !== 'object' || value === null) { + return false; + } + + try { + return getNodeType(value as Node) === NODE_TYPE.documentFragment; + } catch (_) { + return false; + } + }; + /** * Checks whether the given object is a DOM node, including nodes that * originate from a different window/realm (e.g. an iframe's @@ -1282,8 +1377,14 @@ function createDOMPurify(window: WindowLike = getGlobal()): DOMPurify { return true; } - /* Check whether element has a valid namespace */ - if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) { + /* Check whether element has a valid namespace. + Realm-safe check (GHSA-hpcv-96wg-7vj8): use the cached Node.prototype + nodeType getter rather than `instanceof Element`, which is realm- + bound and short-circuits to false for any node minted in a different + realm — letting a foreign-realm element with a forbidden namespace + slip past the namespace check entirely. */ + const nt = getNodeType ? getNodeType(currentNode) : currentNode.nodeType; + if (nt === NODE_TYPE.element && !_checkValidNamespace(currentNode)) { _forceRemove(currentNode); return true; } @@ -1646,8 +1747,11 @@ function createDOMPurify(window: WindowLike = getGlobal()): DOMPurify { /* Check attributes next */ _sanitizeAttributes(shadowNode); - /* Deep shadow DOM detected */ - if (shadowNode.content instanceof DocumentFragment) { + /* Deep shadow DOM detected. + Realm-safe check (GHSA-hpcv-96wg-7vj8): use nodeType against the + DOCUMENT_FRAGMENT_NODE constant rather than instanceof, so we + recurse into <template>.content from foreign realms too. */ + if (_isDocumentFragment(shadowNode.content)) { _sanitizeShadowDOM(shadowNode.content); } } @@ -1673,25 +1777,48 @@ function createDOMPurify(window: WindowLike = getGlobal()): DOMPurify { * existing _sanitizeShadowDOM template-content recursion) stay * untouched — string-input paths are not affected. * + * DOM-Clobbering hardening: HTMLFormElement carries the WebIDL + * [LegacyOverrideBuiltIns] extended attribute, so a descendant element + * named `nodeType`, `shadowRoot`, or `childNodes` shadows the matching + * prototype getter on the form. Reading those properties directly off + * the node would let an attacker steer this walk past shadow hosts + * (e.g. <input name="childNodes"> collapses the form's child list to + * the input itself, so descent stops dead and any shadow root deeper + * in the subtree is never sanitized). Every property access here is + * therefore routed through the cached prototype getter; the form's + * named-property getter cannot intercept those reads. + * * @param root the subtree root to walk for attached shadow roots */ const _sanitizeAttachedShadowRoots = function (root: Node): void { - if ( - root.nodeType === NODE_TYPE.element && - (root as Element).shadowRoot instanceof DocumentFragment - ) { - const sr = (root as Element).shadowRoot as DocumentFragment; - // Recurse first so that nested shadow roots are reached even if - // _sanitizeShadowDOM removes hosts at this level. - _sanitizeAttachedShadowRoots(sr); - _sanitizeShadowDOM(sr); + const nodeType = getNodeType ? getNodeType(root) : (root as any).nodeType; + + if (nodeType === NODE_TYPE.element) { + const sr = getShadowRoot + ? getShadowRoot(root) + : (root as Element).shadowRoot; + // Realm-safe check (GHSA-hpcv-96wg-7vj8): use nodeType-based + // detection rather than `instanceof DocumentFragment`, which is + // realm-bound and silently skipped shadow roots whose host element + // belonged to a foreign realm (e.g. iframe.contentDocument + // attachShadow). A foreign-realm ShadowRoot extends the foreign + // realm's DocumentFragment, not ours, so the old instanceof check + // returned false and the shadow subtree was never walked. + if (_isDocumentFragment(sr)) { + // Recurse first so that nested shadow roots are reached even if + // _sanitizeShadowDOM removes hosts at this level. + _sanitizeAttachedShadowRoots(sr); + _sanitizeShadowDOM(sr); + } } // Snapshot children before recursing. Sanitization of one subtree // (e.g. via an uponSanitizeShadowNode hook) may detach siblings, // and naive nextSibling traversal would silently skip the rest of // the list once a node is detached. - const childNodes = root.childNodes; + const childNodes = getChildNodes + ? getChildNodes(root) + : (root as Element).childNodes; if (!childNodes) { return; } @@ -1748,8 +1875,14 @@ function createDOMPurify(window: WindowLike = getGlobal()): DOMPurify { } if (IN_PLACE) { - /* Do some early pre-sanitization to avoid unsafe root nodes */ - const nn = (dirty as Node).nodeName; + /* Do some early pre-sanitization to avoid unsafe root nodes. + Read nodeName through the cached prototype getter — a clobbering + child named "nodeName" on the form root would otherwise shadow + the property and let this check skip the root-allowlist + validation entirely. */ + const nn = getNodeName + ? getNodeName(dirty as Node) + : (dirty as Node).nodeName; if (typeof nn === 'string') { const tagName = transformCaseFunc(nn); if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) { @@ -1759,6 +1892,22 @@ function createDOMPurify(window: WindowLike = getGlobal()): DOMPurify { } } + /* Pre-flight the root through _isClobbered. The iterator-driven + removal path can not detach a parent-less root: _forceRemove + falls through to Element.prototype.remove(), which per spec + is a no-op on a node with no parent. A clobbered root would + then survive the main loop with its attributes uninspected, + because _sanitizeAttributes early-returns on _isClobbered. The + result would be an attacker-controlled form, complete with any + event-handler attributes the caller passed in, handed back to + the application unsanitized. Refuse to sanitize such a root + the same way we refuse a forbidden tag. GHSA-r47g-fvhr-h676. */ + if (_isClobbered(dirty as Element)) { + throw typeErrorCreate( + 'root node is clobbered and cannot be sanitized in-place' + ); + } + /* Sanitize attached shadow roots before the main iterator runs. The iterator does not descend into shadow trees. */ _sanitizeAttachedShadowRoots(dirty as Node); @@ -1782,7 +1931,9 @@ function createDOMPurify(window: WindowLike = getGlobal()): DOMPurify { /* Clonable shadow roots are deep-cloned by importNode(); sanitize them before the main iterator runs, since the iterator does not - descend into shadow trees. */ + descend into shadow trees. The walk routes every read through a + cached prototype getter so clobbering descendants on a form root + cannot hide a shadow host from this pass. */ _sanitizeAttachedShadowRoots(importedNode); } else { /* Exit directly if we have nothing to do */ @@ -1823,8 +1974,11 @@ function createDOMPurify(window: WindowLike = getGlobal()): DOMPurify { /* Check attributes next */ _sanitizeAttributes(currentNode); - /* Shadow DOM detected, sanitize it */ - if (currentNode.content instanceof DocumentFragment) { + /* Shadow DOM detected, sanitize it. + Realm-safe check (GHSA-hpcv-96wg-7vj8): nodeType-based detection + instead of instanceof, so foreign-realm <template>.content is + walked correctly. */ + if (_isDocumentFragment(currentNode.content)) { _sanitizeShadowDOM(currentNode.content); } }
test/test-suite.js+920 −14 modified@@ -3017,23 +3017,29 @@ QUnit.test( 'Config-Flag tests: IN_PLACE handles DOM-clobbered nodeName safely', function (assert) { - // <input name=nodeName> in a form clobbers form.nodeName in most - // browsers. The IN_PLACE path must handle this without producing a - // sanitized output that still contains attacker-controlled handlers. - var dirty = document.createElement('form'); - dirty.innerHTML = + // Build the clobbering candidate. + var root = document.createElement('form'); + root.innerHTML = '<input name="nodeName" onclick="alert(1)">' + '<input name="attributes" onclick="alert(2)">'; - try { - DOMPurify.sanitize(dirty, { IN_PLACE: true }); - } catch (e) { - // Either throwing OR scrubbing is acceptable; only script execution - // would be unacceptable. + + var clobbersNodeName = typeof root.nodeName !== 'string'; + + if (clobbersNodeName) { + assert.throws( + function () { + DOMPurify.sanitize(root, { IN_PLACE: true }); + }, + /clobbered|forbidden/i, + 'clobbered IN_PLACE root must throw in clobbering-capable engines' + ); + } else { + var clean = DOMPurify.sanitize(root, { IN_PLACE: true }); + assert.ok( + !/on\w+=/i.test(clean.outerHTML), + 'no on-handler survived: ' + clean.outerHTML + ); } - assert.notOk( - /\son[a-z]+\s*=/i.test(dirty.innerHTML), - 'no on-handler survived: ' + dirty.innerHTML - ); } ); @@ -3590,5 +3596,905 @@ document.body.removeChild(iframe); } ); + + QUnit.test( + 'selectedcontent: refresh-after-sanitize bypass is closed (CVE: 3.4.4 → 3.4.5)', + (assert) => { + // --- 1. Exact PoC from KabirAcharya's report. ---------------------------- + // In Chromium/WebKit, <selectedcontent> inside <select> is populated with + // a browser-generated clone of the selected <option>'s children. If the + // iterator visits the clone first and DOMPurify later mutates the option + // (e.g., removes an invalid attribute), the browser refreshes the clone + // from the still-unsanitized option content, after the walk has passed. + // + // Pre-3.4.5, the sanitized return string contained + // <selectedcontent><img onerror=...>x</selectedcontent>. Reinserting that + // via innerHTML fires the handler before the live DOM gets a chance to + // re-strip it. The fix removes <selectedcontent> from the default + // allow-list; the element and its content must not survive. + const exactPoC = + '<select><button><selectedcontent></selectedcontent></button>' + + '<option selected=javascript:1>' + + '<img src=x onerror=alert(1)>x' + + '</option></select>'; + const cleanedPoC = DOMPurify.sanitize(exactPoC); + assert.notOk( + /onerror/i.test(cleanedPoC), + 'exact PoC: no onerror= in sanitized output' + ); + assert.notOk( + /<selectedcontent/i.test(cleanedPoC), + 'exact PoC: <selectedcontent> stripped from default-config output' + ); + + // --- 2. Generalised trigger family. -------------------------------------- + // The clone-refresh isn't unique to the `selected` attribute. Any mutation + // DOMPurify performs on the source <option> can in principle re-pollute + // an already-walked <selectedcontent> sibling. Each of the below removes a + // different attribute or child from the option during sanitization. If a + // future patch only handles the `selected` attribute path specifically, + // these variants would still bypass — this guards against that. + const triggerVariants = [ + // Stripped attribute on the option itself. + '<select><selectedcontent></selectedcontent>' + + '<option onclick=alert(1)><img src=x onerror=alert(1)>y</option></select>', + // Stripped child element of the option. + '<select><selectedcontent></selectedcontent>' + + '<option><script>alert(1)<\/script>' + + '<img src=x onerror=alert(1)>z</option></select>', + // Stripped forbidden attribute on a nested element of the option. + '<select><selectedcontent></selectedcontent>' + + '<option><a href=javascript:alert(1)>' + + '<img src=x onerror=alert(1)>w</a></option></select>', + ]; + triggerVariants.forEach((dirty, i) => { + const out = DOMPurify.sanitize(dirty); + assert.notOk( + /onerror/i.test(out), + 'trigger variant ' + i + ': no onerror= survives sanitization' + ); + assert.notOk( + /<selectedcontent/i.test(out), + 'trigger variant ' + i + ': <selectedcontent> removed' + ); + }); + + // --- 3. Live-DOM behaviour check. --------------------------------------- + // The full impact requires reinserting the sanitized string. Confirm the + // round-trip doesn't fire handlers. This is what callers actually do: + // sanitize(...), then element.innerHTML = result. + let alertFired = false; + const originalAlert = window.alert; + window.alert = () => { + alertFired = true; + }; + try { + const host = document.createElement('div'); + host.innerHTML = DOMPurify.sanitize(exactPoC); + // Force any pending image-load error handlers to run by attaching to DOM. + document.body.appendChild(host); + // Tick the event loop synchronously where possible. img.onerror fires + // synchronously in most browsers when src is unreachable; if a test + // runner needs an await tick here, wrap the test in QUnit.test.async. + document.body.removeChild(host); + } finally { + window.alert = originalAlert; + } + assert.notOk( + alertFired, + 'round-trip (sanitize → innerHTML) does not execute attacker handler' + ); + + // --- 4. Opt-in path still works for callers who explicitly allow it. ----- + // The fix should be removing <selectedcontent> from defaults, not banning + // it entirely. Users who pass it through ADD_TAGS should still be able to + // use it for plain (non-attack) content. If a future fix removes this + // capability outright, this assertion will catch the over-correction. + const benign = '<selectedcontent>hello</selectedcontent>'; + const benignClean = DOMPurify.sanitize(benign, { + ADD_TAGS: ['selectedcontent'], + }); + assert.ok( + /<selectedcontent[^>]*>hello<\/selectedcontent>/i.test(benignClean), + 'ADD_TAGS opt-in: benign <selectedcontent> content survives' + ); + } + ); + + /* + * Regression tests for DOM Clobbering bypass of attached-shadow-root sanitization. + * + * Drop this block into test/test-suite.js (anywhere after the existing + * QUnit.module declarations). It owns its own module so the test labels do + * not leak the name of whatever module preceded it in the suite. + * + * Environment notes: + * - The DOMPurify Node test runner globalizes `document` and `DOMPurify` + * but not `Element`, `Window`, etc. Tests here feature-detect through + * `document` or instance probes to stay portable. + * - HTMLFormElement [LegacyOverrideBuiltIns] named-property clobbering is + * a hard prerequisite for exercising the bug. Some jsdom builds do not + * implement it; in those builds the clobbering-specific tests cannot + * reproduce the issue and skip with a clear message rather than passing + * silently. Browser runs (chromium/webkit/firefox) always implement it. + * - Imperative `attachShadow` + IN_PLACE traversal is also a prerequisite. + * If even that fails (older jsdom where ShadowRoot does not extend + * DocumentFragment), every test below skips — the bug under test is a + * refinement of behavior that has to work in the first place. + * + * Before running locally: + * npm run build # rebuild dist/ from src/purify.ts + * npm run test:jsdom # run only the node-side suite + */ + + QUnit.module('DOM Clobbering of attached-shadow-root traversal'); + + // Cached probe results. Populated by the first test; consulted by the rest. + var __probe = { + ran: false, + shadowSanitization: false, // basic _sanitizeAttachedShadowRoots works + formClobbering: false, // <input name="X"> shadows form.X + setHTMLUnsafe: false, // declarative shadow DOM via setHTMLUnsafe + }; + + function _probeOnce() { + if (__probe.ran) { + return __probe; + } + __probe.ran = true; + + // (1) Does _sanitizeAttachedShadowRoots reach an imperatively-attached + // shadow root under IN_PLACE? Use a fresh host with a known-bad payload + // and check whether DOMPurify scrubs it. + try { + var probeHost = document.createElement('div'); + if (typeof probeHost.attachShadow === 'function') { + probeHost.attachShadow({ mode: 'open' }).innerHTML = + '<img src=x onerror=alert(1)>'; + DOMPurify.sanitize(probeHost, { IN_PLACE: true }); + __probe.shadowSanitization = + probeHost.shadowRoot && + probeHost.shadowRoot.querySelectorAll('img').length === 0; + } + } catch (_) {} + + // (2) Does HTMLFormElement implement named-property clobbering? + try { + var probeForm = document.createElement('form'); + var probeInput = document.createElement('input'); + probeInput.setAttribute('name', 'childNodes'); + probeForm.appendChild(probeInput); + // In a clobbering-capable engine, form.childNodes is *replaced* by the + // named child (the input element or a RadioNodeList around it) and no + // longer behaves as a NodeList of length 1 whose [0] is the input. + var cn = probeForm.childNodes; + var looksLikeRealChildNodes = + cn && typeof cn.length === 'number' && cn[0] === probeInput; + __probe.formClobbering = !looksLikeRealChildNodes; + } catch (_) {} + + // (3) Is declarative shadow DOM via setHTMLUnsafe available? Probe on + // an instance to avoid depending on a global `Element` reference. + try { + var probeContainer = document.createElement('div'); + __probe.setHTMLUnsafe = + typeof probeContainer.setHTMLUnsafe === 'function'; + } catch (_) {} + + return __probe; + } + + QUnit.test( + 'environment probe: report shadow-DOM and form-clobbering support', + function (assert) { + var p = _probeOnce(); + // Each probe is reported as its own assertion so the test log makes the + // capability picture obvious if anything below skips. + assert.ok(true, 'shadowSanitization=' + p.shadowSanitization); + assert.ok(true, 'formClobbering=' + p.formClobbering); + assert.ok(true, 'setHTMLUnsafe=' + p.setHTMLUnsafe); + } + ); + + // --------------------------------------------------------------------------- + // Bypass-specific tests. They REQUIRE both shadow sanitization and form + // clobbering to be supported — otherwise the bug under test cannot be + // reproduced in this engine, and we skip rather than silently pass. + // --------------------------------------------------------------------------- + + function _skipIfMissingPrereqs(assert) { + var p = _probeOnce(); + if (!p.shadowSanitization) { + assert.ok( + true, + 'SKIP: this engine does not sanitize attached shadow roots via IN_PLACE; the bug under test is below the prerequisite' + ); + return true; + } + if (!p.formClobbering) { + assert.ok( + true, + 'SKIP: this engine does not implement HTMLFormElement [LegacyOverrideBuiltIns] named-property clobbering; the bypass is not reproducible here (browser runs cover it)' + ); + return true; + } + return false; + } + + QUnit.test( + 'IN_PLACE: form clobbered by name="childNodes" does not hide a shadow root', + function (assert) { + if (_skipIfMissingPrereqs(assert)) return; + + var host = document.createElement('div'); + host.attachShadow({ mode: 'open' }).innerHTML = + '<img src=x onerror="window.__pwned_childNodes=1">'; + + var form = document.createElement('form'); + var clobber = document.createElement('input'); + clobber.setAttribute('name', 'childNodes'); + form.appendChild(clobber); + form.appendChild(host); + + DOMPurify.sanitize(form, { IN_PLACE: true }); + + assert.notOk( + host.shadowRoot && host.shadowRoot.querySelector('img'), + 'onerror <img> must not survive inside the attached shadow root' + ); + } + ); + + QUnit.test( + 'IN_PLACE: form clobbered by name="nodeType" does not hide a shadow root', + function (assert) { + if (_skipIfMissingPrereqs(assert)) return; + + var host = document.createElement('div'); + host.attachShadow({ mode: 'open' }).innerHTML = + '<img src=x onerror="window.__pwned_nodeType=1">'; + + var form = document.createElement('form'); + var clobber = document.createElement('input'); + clobber.setAttribute('name', 'nodeType'); + form.appendChild(clobber); + form.appendChild(host); + + DOMPurify.sanitize(form, { IN_PLACE: true }); + + assert.notOk( + host.shadowRoot && host.shadowRoot.querySelector('img'), + 'onerror <img> must not survive inside the attached shadow root' + ); + } + ); + + QUnit.test( + 'IN_PLACE: form clobbered by name="shadowRoot" does not hide its descendant host shadow root', + function (assert) { + if (_skipIfMissingPrereqs(assert)) return; + + var host = document.createElement('div'); + host.attachShadow({ mode: 'open' }).innerHTML = + '<img src=x onerror="window.__pwned_shadowRoot=1">'; + + var form = document.createElement('form'); + var clobber = document.createElement('input'); + clobber.setAttribute('name', 'shadowRoot'); + form.appendChild(clobber); + form.appendChild(host); + + DOMPurify.sanitize(form, { IN_PLACE: true }); + + assert.notOk( + host.shadowRoot && host.shadowRoot.querySelector('img'), + 'onerror <img> must not survive inside the attached shadow root' + ); + } + ); + + QUnit.test( + 'IN_PLACE: nodeName-clobbered root is rejected regardless of allowlist', + function (assert) { + var p = _probeOnce(); + if (!p.formClobbering) { + assert.ok(true, 'SKIP: no form clobbering in this engine'); + return; + } + + // After GHSA-r47g-fvhr-h676, a clobbered form root is rejected by the + // IN_PLACE preamble's _isClobbered pre-flight, independent of the tag + // allowlist. So both cases below must throw: + // 1. allowed tag (form is in the default allowlist) but clobbered + // 2. forbidden tag (form excluded via FORBID_TAGS) and clobbered + // The earlier draft of this test asserted case 1 must NOT throw — that + // expectation predated the GHSA-r47g-fvhr-h676 fix and was wrong. + + // Case 1: allowed tag, clobbered → must throw (clobbering check fires). + var allowedRoot = document.createElement('form'); + var clobberA = document.createElement('input'); + clobberA.setAttribute('name', 'nodeName'); + allowedRoot.appendChild(clobberA); + + assert.throws(function () { + DOMPurify.sanitize(allowedRoot, { IN_PLACE: true }); + }, 'allowed-tag clobbered root must throw'); + + // Case 2: forbidden tag AND clobbered → must throw. The exact error + // message depends on which check fires first (allowlist vs clobbering + // pre-flight); both are correct refusals. + var forbiddenRoot = document.createElement('form'); + var clobberB = document.createElement('input'); + clobberB.setAttribute('name', 'nodeName'); + forbiddenRoot.appendChild(clobberB); + + assert.throws(function () { + DOMPurify.sanitize(forbiddenRoot, { + IN_PLACE: true, + FORBID_TAGS: ['form'], + }); + }, 'forbidden-tag clobbered root must throw'); + } + ); + + QUnit.test( + 'DOM-node input (no IN_PLACE): clobbered form does not hide a clonable shadow root', + function (assert) { + var p = _probeOnce(); + if (!p.formClobbering) { + assert.ok(true, 'SKIP: no form clobbering in this engine'); + return; + } + + var host = document.createElement('div'); + if (typeof host.attachShadow !== 'function') { + assert.ok(true, 'SKIP: attachShadow not available'); + return; + } + try { + host.attachShadow({ mode: 'open', clonable: true }).innerHTML = + '<img src=x onerror="window.__pwned_import=1">'; + } catch (_) { + assert.ok(true, 'SKIP: clonable shadow roots not supported here'); + return; + } + + var form = document.createElement('form'); + var clobber = document.createElement('input'); + clobber.setAttribute('name', 'childNodes'); + form.appendChild(clobber); + form.appendChild(host); + + var clean = DOMPurify.sanitize(form); // not IN_PLACE — node-input path + var probe = document.createElement('div'); + if (typeof clean === 'string') { + probe.innerHTML = clean; + } + assert.equal( + probe.querySelectorAll('img[src="x"][onerror]').length, + 0, + 'onerror <img> must not survive via the node-input path' + ); + } + ); + + QUnit.test( + 'setHTMLUnsafe + IN_PLACE: declarative shadow DOM under a clobbered form is sanitized', + function (assert) { + var p = _probeOnce(); + if (!p.setHTMLUnsafe) { + assert.ok(true, 'SKIP: setHTMLUnsafe not available in this engine'); + return; + } + if (!p.formClobbering) { + assert.ok(true, 'SKIP: no form clobbering in this engine'); + return; + } + + var container = document.createElement('div'); + container.setHTMLUnsafe( + '<form>' + + '<input name="childNodes">' + + '<div id="host">' + + '<template shadowrootmode="open">' + + '<img src=x onerror="window.__pwned_setHTMLUnsafe=1">' + + '</template>' + + '</div>' + + '</form>' + ); + + DOMPurify.sanitize(container, { IN_PLACE: true }); + + var host = container.querySelector('#host'); + var img = + host && host.shadowRoot && host.shadowRoot.querySelector('img'); + assert.notOk( + img, + 'shadow-root <img> from declarative shadow DOM must be sanitized' + ); + } + ); + + // --------------------------------------------------------------------------- + // _isClobbered defense-in-depth. + // --------------------------------------------------------------------------- + + QUnit.test( + '_isClobbered: form with name="childNodes" child is removed during sanitization', + function (assert) { + var p = _probeOnce(); + if (!p.formClobbering) { + assert.ok(true, 'SKIP: no form clobbering in this engine'); + return; + } + + var form = document.createElement('form'); + var clobber = document.createElement('input'); + clobber.setAttribute('name', 'childNodes'); + form.appendChild(clobber); + + var wrapper = document.createElement('div'); + wrapper.appendChild(form); + + DOMPurify.sanitize(wrapper, { IN_PLACE: true }); + + assert.equal( + wrapper.querySelectorAll('form').length, + 0, + 'clobbered form must be removed' + ); + } + ); + + QUnit.test( + '_isClobbered: form clobbered by <select name="childNodes"> is still removed', + function (assert) { + // <select> defeats a naive `typeof childNodes.length === "number"` + // probe because HTMLSelectElement.length is a defined unsigned-long + // attribute returning the option count. The probe must instead compare + // the direct read against the cached Node.prototype getter, which is + // type-agnostic and catches every clobbering child. + var p = _probeOnce(); + if (!p.formClobbering) { + assert.ok(true, 'SKIP: no form clobbering in this engine'); + return; + } + + var form = document.createElement('form'); + var clobber = document.createElement('select'); + clobber.setAttribute('name', 'childNodes'); + form.appendChild(clobber); + + var wrapper = document.createElement('div'); + wrapper.appendChild(form); + + DOMPurify.sanitize(wrapper, { IN_PLACE: true }); + + assert.equal( + wrapper.querySelectorAll('form').length, + 0, + 'form clobbered by <select name="childNodes"> must be removed' + ); + } + ); + + QUnit.test( + '_isClobbered: shadow root nested under a <select>-clobbered form is still sanitized', + function (assert) { + // End-to-end version of the <select> probe defeat: confirms the actual + // XSS impact is still blocked. The primary defense — cached prototype + // getters in _sanitizeAttachedShadowRoots — handles this regardless of + // _isClobbered, so this test passes even with the old length-based + // probe. We keep it so a future regression in the traversal would be + // visible alongside the _isClobbered hardening. + var p = _probeOnce(); + if (!p.formClobbering || !p.shadowSanitization) { + assert.ok(true, 'SKIP: missing prerequisites in this engine'); + return; + } + + var host = document.createElement('div'); + host.attachShadow({ mode: 'open' }).innerHTML = + '<img src=x onerror="window.__pwned_select=1">'; + + var form = document.createElement('form'); + var clobber = document.createElement('select'); + clobber.setAttribute('name', 'childNodes'); + form.appendChild(clobber); + form.appendChild(host); + + DOMPurify.sanitize(form, { IN_PLACE: true }); + + assert.notOk( + host.shadowRoot && host.shadowRoot.querySelector('img'), + 'onerror <img> must not survive inside the attached shadow root' + ); + } + ); + + // --------------------------------------------------------------------------- + // GHSA-r47g-fvhr-h676 — parent-less clobbered IN_PLACE root retains + // attacker-controlled attributes. When _forceRemove can't detach the root + // (no parent) and _sanitizeAttributes early-returns on _isClobbered, any + // event-handler attribute on the root survives. sanitize() must instead + // throw on a clobbered IN_PLACE root, the same way it throws on a + // forbidden root tag. + // --------------------------------------------------------------------------- + + QUnit.test( + 'GHSA-r47g-fvhr-h676: parent-less clobbered form root throws instead of returning the root with onmouseover intact', + function (assert) { + var p = _probeOnce(); + if (!p.formClobbering) { + assert.ok(true, 'SKIP: no form clobbering in this engine'); + return; + } + + // Build the report's PoC: parent-less <form onmouseover=...> with an + // <input name="nodeName"> child that clobbers form.nodeName. The + // patched sanitize() must throw; an attacker should not get back a + // form carrying the event-handler attribute. + // + // The throw IS the protection: by refusing to return the root, the + // sanitizer makes it impossible for the caller to insert an + // attacker-controlled element into the live DOM. We do NOT assert + // anything about the root's attributes afterwards — the fix is + // "fail closed, don't hand back this node", not "scrub then return". + // Asserting onmouseover is gone would be incorrect: the throw fires + // in the preamble before any attribute walk, so the input node is + // unchanged, by design. + var root = document.createElement('form'); + root.setAttribute('onmouseover', 'window.__rooted_h676 = 1'); + var clobber = document.createElement('input'); + clobber.setAttribute('name', 'nodeName'); + root.appendChild(clobber); + + assert.throws(function () { + DOMPurify.sanitize(root, { IN_PLACE: true }); + }, 'clobbered parent-less IN_PLACE root must throw'); + } + ); + + QUnit.test( + 'GHSA-r47g-fvhr-h676: each clobbering name covered by _isClobbered triggers the IN_PLACE preamble throw', + function (assert) { + var p = _probeOnce(); + if (!p.formClobbering) { + assert.ok(true, 'SKIP: no form clobbering in this engine'); + return; + } + + // The report enumerates "nodeName | setAttribute | namespaceURI | + // insertBefore | hasChildNodes | childNodes" as PoC seeds. Each name + // is in _isClobbered's typing checklist, so the preamble must throw + // for each of them when the root is parent-less. + var clobberNames = [ + 'nodeName', + 'setAttribute', + 'namespaceURI', + 'insertBefore', + 'hasChildNodes', + 'childNodes', + ]; + + clobberNames.forEach(function (name) { + var root = document.createElement('form'); + root.setAttribute('onmouseover', 'window.__rooted_' + name + ' = 1'); + var clobber = document.createElement('input'); + clobber.setAttribute('name', name); + root.appendChild(clobber); + + assert.throws( + function () { + DOMPurify.sanitize(root, { IN_PLACE: true }); + }, + 'IN_PLACE preamble must throw for clobber name="' + name + '"' + ); + }); + } + ); + + QUnit.test( + 'GHSA-r47g-fvhr-h676: a parented clobbered form is still sanitized normally (regression guard)', + function (assert) { + var p = _probeOnce(); + if (!p.formClobbering) { + assert.ok(true, 'SKIP: no form clobbering in this engine'); + return; + } + + // Sanity-check that the preamble fix is narrowly scoped: when the + // IN_PLACE root is NOT the clobbered form (it's a wrapper that + // contains it), the iterator-driven removal path works normally — + // _forceRemove succeeds because the form has a parent — and the + // application should not see any error. + var wrapper = document.createElement('div'); + var form = document.createElement('form'); + form.setAttribute('onmouseover', 'window.__rooted_parented = 1'); + var clobber = document.createElement('input'); + clobber.setAttribute('name', 'nodeName'); + form.appendChild(clobber); + wrapper.appendChild(form); + + DOMPurify.sanitize(wrapper, { IN_PLACE: true }); + + assert.equal( + wrapper.querySelectorAll('form').length, + 0, + 'parented clobbered form is removed by the iterator-driven path' + ); + // The form was detached; no chance for onmouseover to fire. + } + ); + + // --------------------------------------------------------------------------- + // Regression guards. These exercise behaviour that must hold independent of + // the clobbering fix, so the patch does not silently regress ordinary + // attached-shadow-root sanitization. They skip if the engine can't sanitize + // shadow roots at all (older jsdom), which is reported by the probe. + // --------------------------------------------------------------------------- + + QUnit.test( + 'Regression guard: ordinary attached shadow roots are still sanitized in-place', + function (assert) { + var p = _probeOnce(); + if (!p.shadowSanitization) { + assert.ok( + true, + 'SKIP: this engine does not sanitize attached shadow roots via IN_PLACE' + ); + return; + } + + var host = document.createElement('div'); + host.attachShadow({ mode: 'open' }).innerHTML = + '<img src=x onerror=alert(1)><b>kept</b>'; + + DOMPurify.sanitize(host, { IN_PLACE: true }); + + assert.equal( + host.shadowRoot.querySelectorAll('img').length, + 0, + 'onerror <img> is removed' + ); + assert.equal( + host.shadowRoot.querySelector('b').textContent, + 'kept', + 'safe content is preserved' + ); + } + ); + + QUnit.test( + 'Regression guard: nested attached shadow roots are still reached', + function (assert) { + var p = _probeOnce(); + if (!p.shadowSanitization) { + assert.ok( + true, + 'SKIP: this engine does not sanitize attached shadow roots via IN_PLACE' + ); + return; + } + + var outer = document.createElement('div'); + var outerRoot = outer.attachShadow({ mode: 'open' }); + var inner = document.createElement('section'); + outerRoot.appendChild(inner); + inner.attachShadow({ mode: 'open' }).innerHTML = + '<img src=x onerror=alert(2)>'; + + DOMPurify.sanitize(outer, { IN_PLACE: true }); + + assert.equal( + inner.shadowRoot.querySelectorAll('img').length, + 0, + 'onerror <img> inside a nested shadow root is removed' + ); + } + ); + + // --------------------------------------------------------------------------- + // GHSA-hpcv-96wg-7vj8 — cross-realm IN_PLACE sanitization. Foreign-realm + // nodes (e.g. <form>, <template>, attached shadow roots from a same-origin + // iframe document) reach DOMPurify via the realm-agnostic _isNode check + // at the entry point, but several downstream security branches used to + // gate on `instanceof X` against parent-realm constructors. Each gate + // short-circuited to false for foreign-realm objects and the relevant + // sanitization branch was skipped: form clobbering went undetected, + // <template>.content was never walked, attached shadow roots were never + // walked. The fix routes every such decision through realm-independent + // shape checks (cached prototype getters, nodeType comparisons). + // + // These tests are gated on the ability to construct a same-origin iframe + // document, which works in real browsers and modern jsdom. They skip + // gracefully if the environment can't host an iframe (e.g. some Node + // setups). + // --------------------------------------------------------------------------- + + function _withForeignRealmDoc(callback) { + // Returns a foreign-realm document for the test, plus a teardown. + // Returns null if the environment can't provide one — caller skips. + if (typeof document.createElement !== 'function') { + return null; + } + try { + var iframe = document.createElement('iframe'); + // Empty srcdoc gives us a clean same-origin document with body/head. + iframe.srcdoc = '<!doctype html><html><body></body></html>'; + if (document.body) { + document.body.appendChild(iframe); + } else { + // No live body — can't host an iframe load. Skip. + return null; + } + var foreignDoc = iframe.contentDocument; + if (!foreignDoc) { + iframe.remove(); + return null; + } + try { + callback(foreignDoc, iframe.contentWindow); + } finally { + iframe.remove(); + } + return true; + } catch (_) { + return null; + } + } + + QUnit.test( + 'GHSA-hpcv-96wg-7vj8: cross-realm clobbered form is recognized by _isClobbered', + function (assert) { + var ran = _withForeignRealmDoc(function (idoc) { + var foreignForm = idoc.createElement('form'); + foreignForm.setAttribute('onmouseover', 'window.__hpcv_form_xss = 1'); + var clobber = idoc.createElement('input'); + clobber.setAttribute('name', 'attributes'); + foreignForm.appendChild(clobber); + + // Capability probe inside the foreign realm: does this engine + // actually implement [LegacyOverrideBuiltIns] for HTMLFormElement? + // jsdom (at least up to 29.x) does not, so .attributes is never + // shadowed and there is nothing to detect. Real browsers do, and + // the patched _isClobbered must catch it via the cached-getter + // equality probe even though the form is from a foreign realm. + // + // typeof on the canonical NamedNodeMap is 'object'. On a clobbered + // form .attributes becomes the <input> element — still typeof + // 'object' — so we check identity instead: foreignForm.attributes + // is the input if (and only if) the engine performs the shadowing. + var foreignClobbers = foreignForm.attributes === clobber; + if (!foreignClobbers) { + assert.ok( + true, + 'SKIP: foreign realm does not implement HTMLFormElement ' + + '[LegacyOverrideBuiltIns]; the bypass is not reproducible here' + ); + return; + } + + // Pre-fix: the parent-realm DOMPurify sees this foreign-realm + // form, the `instanceof HTMLFormElement` check short-circuits to + // false in _isClobbered, the form is not flagged, and the + // onmouseover attribute survives (because the attribute walk + // reads the clobbered .attributes collection rather than the + // real one). After the fix the tag-name probe via cached + // Node.prototype getter identifies the foreign-realm form, and + // the cached-getter equality probe on .attributes detects the + // clobbering. + assert.throws( + function () { + DOMPurify.sanitize(foreignForm, { IN_PLACE: true }); + }, + /clobbered|forbidden/i, + 'foreign-realm clobbered form must throw on IN_PLACE' + ); + }); + if (!ran) { + assert.ok(true, 'SKIP: cannot construct a foreign-realm document'); + } + } + ); + + QUnit.test( + 'GHSA-hpcv-96wg-7vj8: cross-realm <template>.content is walked and sanitized', + function (assert) { + var ran = _withForeignRealmDoc(function (idoc) { + var wrapper = idoc.createElement('div'); + var tpl = idoc.createElement('template'); + tpl.innerHTML = '<img src="x" onerror="window.__hpcv_tpl_xss = 1">'; + wrapper.appendChild(tpl); + + // Pre-fix the `template.content instanceof DocumentFragment` check + // failed for the foreign-realm fragment, so its contents were never + // walked and the onerror handler survived inside the template body. + DOMPurify.sanitize(wrapper, { IN_PLACE: true }); + + // After the fix the content is walked. The <img> retains src="x" + // (a benign src is allowed) but its onerror attribute is stripped. + var img = tpl.content.querySelector('img'); + assert.ok(img, 'template content was reached'); + assert.equal( + img.getAttribute('onerror'), + null, + 'onerror inside foreign-realm <template> must be stripped' + ); + }); + if (!ran) { + assert.ok(true, 'SKIP: cannot construct a foreign-realm document'); + } + } + ); + + QUnit.test( + 'GHSA-hpcv-96wg-7vj8: cross-realm attached shadow root is walked and sanitized', + function (assert) { + var ran = _withForeignRealmDoc(function (idoc) { + var host = idoc.createElement('div'); + if (typeof host.attachShadow !== 'function') { + assert.ok( + true, + 'SKIP: foreign realm does not support attachShadow' + ); + return; + } + host.attachShadow({ mode: 'open' }).innerHTML = + '<img src=x onerror="window.__hpcv_shadow_xss=1"><b>safe</b>'; + + // Pre-fix the `sr instanceof DocumentFragment` check in + // _sanitizeAttachedShadowRoots failed for the foreign-realm shadow + // root and the whole shadow subtree was skipped. The handler then + // fired the moment the host was inserted into the live document. + DOMPurify.sanitize(host, { IN_PLACE: true }); + + var img = host.shadowRoot && host.shadowRoot.querySelector('img'); + // The <img> tag survives (with sanitized attrs) — the assertion is + // specifically about the onerror handler being stripped. + if (img) { + assert.equal( + img.getAttribute('onerror'), + null, + 'onerror inside foreign-realm shadow root must be stripped' + ); + } else { + assert.ok( + true, + 'shadow root contents removed entirely — also acceptable' + ); + } + }); + if (!ran) { + assert.ok(true, 'SKIP: cannot construct a foreign-realm document'); + } + } + ); + + QUnit.test( + 'GHSA-hpcv-96wg-7vj8: cross-realm Element with forbidden namespace is removed', + function (assert) { + var ran = _withForeignRealmDoc(function (idoc) { + // _checkValidNamespace was gated behind `currentNode instanceof + // Element` (parent realm). A foreign-realm element with an + // unallowed namespace would slip past. Confirm the realm-safe + // nodeType-based gate catches it. + var wrapper = idoc.createElement('div'); + var weird = idoc.createElementNS('urn:example:not-allowed', 'weird'); + wrapper.appendChild(weird); + + DOMPurify.sanitize(wrapper, { IN_PLACE: true }); + + assert.equal( + wrapper.getElementsByTagName('weird').length, + 0, + 'foreign-realm bad-namespace element must be removed' + ); + }); + if (!ran) { + assert.ok(true, 'SKIP: cannot construct a foreign-realm document'); + } + } + ); }; });
website/index.html+2 −2 modified@@ -2,7 +2,7 @@ <html lang="en"> <head> <meta charset="UTF-8"> - <title>DOMPurify 3.4.5 "Aftermath"</title> + <title>DOMPurify 3.4.6 "Avalanche"</title> <script src="https://cdn.jsdelivr.net/gh/cure53/DOMPurify@main/dist/purify.js"></script> <!-- we don't actually need it - just to demo and test the $(html) sanitation --> <script src="//code.jquery.com/jquery-3.2.0.min.js"></script> @@ -27,7 +27,7 @@ </script> </head> <body> - <h4>DOMPurify 3.4.5 "Aftermath"</h4> + <h4>DOMPurify 3.4.6 "Avalanche"</h4> <p> <a href="https://www.npmjs.com/package/dompurify"><img src="https://img.shields.io/npm/v/dompurify.svg" alt="npm" /></a> <a href="https://github.com/cure53/DOMPurify/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MPL--2.0%20OR%20Apache--2.0-blue.svg" alt="License" /></a>
Vulnerability mechanics
Root cause
"_forceRemove silently no-ops on parent-less nodes, so the iterator never actually detaches the clobbered root; _sanitizeAttributes then early-returns on the clobbered root without inspecting any attributes, leaving event handlers and other dangerous attributes intact."
Attack vector
An attacker supplies untrusted HTML that parses to a `<form>` element containing a child with `name="nodeName"` (or any of the ten property names `_isClobbered` checks). The `<form>` carries an event-handler attribute such as `onmouseover`. When `DOMPurify.sanitize(root, { IN_PLACE: true })` is called on this detached form, `_forceRemove` cannot detach the parent-less root, `_sanitizeAttributes` early-returns on the clobbered node, and the event handler survives. Re-inserting the sanitized form into the live document triggers XSS. [CWE-79] [ref_id=1]
Affected code
The vulnerability lies in the interaction between `_forceRemove` (src/purify.ts:930-939) and `_sanitizeAttributes` (src/purify.ts:1490-1492). When `DOMPurify.sanitize(root, { IN_PLACE: true })` is called on a detached `<form>` element, `_forceRemove` silently no-ops because the root has no parent. The iterator then calls `_sanitizeAttributes` on the clobbered root, which early-returns without checking any attributes because `_isClobbered(currentNode)` is true. The iterator call site at src/purify.ts:1850-1864 ignores the boolean return value of `_sanitizeElements`, so the attribute walk is never skipped for the root.
What the fix does
The patch at `bb7739e5` ([patch_id=6089182]) addresses the root cause by making `_forceRemove` return a boolean indicating whether the node was actually detached, and having the iterator call site honor that return value. When `_sanitizeElements` returns `true` (node was killed) but `_forceRemove` could not actually detach the root (because it has no parent), the iterator now skips `_sanitizeAttributes` for that node, preventing the early-return bypass. This closes the mismatch between `_forceRemove`'s silent no-op and `_sanitizeAttributes`'s assumption that clobbered nodes have already been removed.
Preconditions
- configThe caller must use DOMPurify.sanitize(node, { IN_PLACE: true }) where node is a detached HTMLFormElement
- inputThe root element must be an HTMLFormElement (which carries [LegacyOverrideBuiltIns])
- inputThe root must contain a descendant element with a name= attribute matching one of the ten property names checked by _isClobbered (e.g., nodeName, setAttribute, namespaceURI, insertBefore, hasChildNodes, childNodes, attributes, textContent, removeChild, removeAttribute)
- networkThe root must have no parent node at the time of sanitization (the standard IN_PLACE case)
Generated on Jun 15, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
2News mentions
0No linked articles in our index yet.