dompurify 3.4.6 → 3.4.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-MPL +373 -0
- package/README.md +19 -2
- package/dist/purify.cjs.d.ts +2 -2
- package/dist/purify.cjs.js +116 -69
- package/dist/purify.cjs.js.map +1 -1
- package/dist/purify.es.d.mts +2 -2
- package/dist/purify.es.mjs +116 -69
- package/dist/purify.es.mjs.map +1 -1
- package/dist/purify.js +116 -69
- package/dist/purify.js.map +1 -1
- package/dist/purify.min.js +2 -2
- package/dist/purify.min.js.map +1 -1
- package/package.json +15 -14
- package/src/config.ts +1 -1
- package/src/purify.ts +141 -66
package/dist/purify.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @license DOMPurify 3.4.
|
|
1
|
+
/*! @license DOMPurify 3.4.8 | (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.8/LICENSE */
|
|
2
2
|
|
|
3
3
|
(function (global, factory) {
|
|
4
4
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
@@ -409,7 +409,7 @@
|
|
|
409
409
|
function createDOMPurify() {
|
|
410
410
|
let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
|
|
411
411
|
const DOMPurify = root => createDOMPurify(root);
|
|
412
|
-
DOMPurify.version = '3.4.
|
|
412
|
+
DOMPurify.version = '3.4.8';
|
|
413
413
|
DOMPurify.removed = [];
|
|
414
414
|
if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
|
|
415
415
|
// Not running in a browser, provide a factory function
|
|
@@ -454,6 +454,23 @@
|
|
|
454
454
|
}
|
|
455
455
|
let trustedTypesPolicy;
|
|
456
456
|
let emptyHTML = '';
|
|
457
|
+
// Tracks whether we are already inside a call to the configured Trusted Types
|
|
458
|
+
// policy's `createHTML`. If the supplied `TRUSTED_TYPES_POLICY.createHTML`
|
|
459
|
+
// itself calls `DOMPurify.sanitize` (the cause of #1422), `sanitize` would
|
|
460
|
+
// re-enter the policy and recurse until the stack overflows. We detect that
|
|
461
|
+
// re-entry and throw a clear, actionable error instead.
|
|
462
|
+
let IN_POLICY_CREATE_HTML = 0;
|
|
463
|
+
const _createTrustedHTML = function _createTrustedHTML(html) {
|
|
464
|
+
if (IN_POLICY_CREATE_HTML > 0) {
|
|
465
|
+
throw typeErrorCreate('The configured TRUSTED_TYPES_POLICY.createHTML must not call ' + 'DOMPurify.sanitize, as that causes infinite recursion. Do not pass ' + 'a policy whose createHTML wraps DOMPurify as TRUSTED_TYPES_POLICY; ' + 'see the "DOMPurify and Trusted Types" section of the README.');
|
|
466
|
+
}
|
|
467
|
+
IN_POLICY_CREATE_HTML++;
|
|
468
|
+
try {
|
|
469
|
+
return trustedTypesPolicy.createHTML(html);
|
|
470
|
+
} finally {
|
|
471
|
+
IN_POLICY_CREATE_HTML--;
|
|
472
|
+
}
|
|
473
|
+
};
|
|
457
474
|
const _document = document,
|
|
458
475
|
implementation = _document.implementation,
|
|
459
476
|
createNodeIterator = _document.createNodeIterator,
|
|
@@ -781,19 +798,47 @@
|
|
|
781
798
|
throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
|
|
782
799
|
}
|
|
783
800
|
// Overwrite existing TrustedTypes policy.
|
|
801
|
+
const previousTrustedTypesPolicy = trustedTypesPolicy;
|
|
784
802
|
trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
|
|
785
|
-
// Sign local variables required by `sanitize`.
|
|
786
|
-
|
|
803
|
+
// Sign local variables required by `sanitize`. If the supplied policy's
|
|
804
|
+
// `createHTML` is circular (i.e. it calls `DOMPurify.sanitize`), this
|
|
805
|
+
// throws via the re-entrancy guard. Restore the previous policy first so
|
|
806
|
+
// the instance is not left in a poisoned state. See #1422.
|
|
807
|
+
try {
|
|
808
|
+
emptyHTML = _createTrustedHTML('');
|
|
809
|
+
} catch (error) {
|
|
810
|
+
trustedTypesPolicy = previousTrustedTypesPolicy;
|
|
811
|
+
throw error;
|
|
812
|
+
}
|
|
787
813
|
} else {
|
|
788
814
|
// Uninitialized policy, attempt to initialize the internal dompurify policy.
|
|
789
|
-
if (trustedTypesPolicy === undefined) {
|
|
815
|
+
if (trustedTypesPolicy === undefined && cfg.TRUSTED_TYPES_POLICY !== null) {
|
|
790
816
|
trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
|
|
791
817
|
}
|
|
792
818
|
// If creating the internal policy succeeded sign internal variables.
|
|
793
|
-
|
|
794
|
-
|
|
819
|
+
// Note: a falsy `trustedTypesPolicy` (null when policy creation failed or
|
|
820
|
+
// was skipped via `TRUSTED_TYPES_POLICY: null`, or undefined when no
|
|
821
|
+
// policy has been initialized yet) must be excluded here, otherwise we
|
|
822
|
+
// would call `.createHTML` on a non-policy and throw. See #1422.
|
|
823
|
+
if (trustedTypesPolicy && typeof emptyHTML === 'string') {
|
|
824
|
+
emptyHTML = _createTrustedHTML('');
|
|
795
825
|
}
|
|
796
826
|
}
|
|
827
|
+
/*
|
|
828
|
+
* Mirror the clone-before-mutate pattern already applied above for
|
|
829
|
+
* cfg.ADD_TAGS / cfg.ADD_ATTR: if any uponSanitize* hook is
|
|
830
|
+
* registered AND the set still points at the default constant,
|
|
831
|
+
* clone it. The hook then mutates the clone (in-call widening
|
|
832
|
+
* still works exactly as documented) and the next default-cfg
|
|
833
|
+
* call rebinds to the untouched original via the reassignment at
|
|
834
|
+
* the top of this function.
|
|
835
|
+
*/
|
|
836
|
+
if ((hooks.uponSanitizeElement.length > 0 || hooks.uponSanitizeAttribute.length > 0) && ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
|
|
837
|
+
ALLOWED_TAGS = clone(ALLOWED_TAGS);
|
|
838
|
+
}
|
|
839
|
+
if (hooks.uponSanitizeAttribute.length > 0 && ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
|
|
840
|
+
ALLOWED_ATTR = clone(ALLOWED_ATTR);
|
|
841
|
+
}
|
|
797
842
|
// Prevent further manipulation of configuration.
|
|
798
843
|
// Not available in IE8, Safari 5, etc.
|
|
799
844
|
if (freeze) {
|
|
@@ -953,7 +998,7 @@
|
|
|
953
998
|
// Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
|
|
954
999
|
dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
|
|
955
1000
|
}
|
|
956
|
-
const dirtyPayload = trustedTypesPolicy ?
|
|
1001
|
+
const dirtyPayload = trustedTypesPolicy ? _createTrustedHTML(dirty) : dirty;
|
|
957
1002
|
/*
|
|
958
1003
|
* Use the DOMParser API by default, fallback later if needs be
|
|
959
1004
|
* DOMParser not work for svg when has multiple root element.
|
|
@@ -1012,7 +1057,8 @@
|
|
|
1012
1057
|
*
|
|
1013
1058
|
* @param node The root element whose character data should be scrubbed.
|
|
1014
1059
|
*/
|
|
1015
|
-
const
|
|
1060
|
+
const _scrubTemplateExpressions2 = function _scrubTemplateExpressions(node) {
|
|
1061
|
+
var _node$querySelectorAl, _node$querySelectorAl2;
|
|
1016
1062
|
node.normalize();
|
|
1017
1063
|
const walker = createNodeIterator.call(node.ownerDocument || node, node,
|
|
1018
1064
|
// eslint-disable-next-line no-bitwise
|
|
@@ -1026,6 +1072,15 @@
|
|
|
1026
1072
|
currentNode.data = data;
|
|
1027
1073
|
currentNode = walker.nextNode();
|
|
1028
1074
|
}
|
|
1075
|
+
// NodeIterator does not descend into <template>.content per the DOM spec,
|
|
1076
|
+
// so we must explicitly recurse into each template's content fragment,
|
|
1077
|
+
// mirroring the approach used by _sanitizeShadowDOM.
|
|
1078
|
+
const templates = (_node$querySelectorAl = (_node$querySelectorAl2 = node.querySelectorAll) === null || _node$querySelectorAl2 === void 0 ? void 0 : _node$querySelectorAl2.call(node, 'template')) !== null && _node$querySelectorAl !== void 0 ? _node$querySelectorAl : [];
|
|
1079
|
+
arrayForEach(Array.from(templates), tmpl => {
|
|
1080
|
+
if (_isDocumentFragment(tmpl.content)) {
|
|
1081
|
+
_scrubTemplateExpressions2(tmpl.content);
|
|
1082
|
+
}
|
|
1083
|
+
});
|
|
1029
1084
|
};
|
|
1030
1085
|
/**
|
|
1031
1086
|
* _isClobbered
|
|
@@ -1036,32 +1091,6 @@
|
|
|
1036
1091
|
* on direct reads. We use this check at the IN_PLACE entry-point and
|
|
1037
1092
|
* during attribute sanitization to refuse clobbered forms.
|
|
1038
1093
|
*
|
|
1039
|
-
* Realm safety (GHSA-hpcv-96wg-7vj8): every check in this function must
|
|
1040
|
-
* work for foreign-realm forms — e.g. a <form> created inside a same-
|
|
1041
|
-
* origin iframe and then handed to a parent-realm DOMPurify instance
|
|
1042
|
-
* with IN_PLACE: true. The original implementation used
|
|
1043
|
-
* `element instanceof HTMLFormElement` and `element.attributes
|
|
1044
|
-
* instanceof NamedNodeMap`, both of which are realm-bound: a foreign-
|
|
1045
|
-
* realm form is an instance of the *foreign* realm's HTMLFormElement,
|
|
1046
|
-
* not the parent realm's. The instanceof short-circuited to false and
|
|
1047
|
-
* the function returned false (= not clobbered) regardless of how
|
|
1048
|
-
* thoroughly the form was clobbered. Sanitize then walked a clobbered
|
|
1049
|
-
* .attributes and missed every attribute on the form root, leaving
|
|
1050
|
-
* onmouseover / onclick / formaction / etc. intact.
|
|
1051
|
-
*
|
|
1052
|
-
* The realm-independent replacements:
|
|
1053
|
-
* - HTMLFormElement detection — read the tag name through the cached
|
|
1054
|
-
* Node.prototype.nodeName getter. WebIDL getters operate on internal
|
|
1055
|
-
* slots that exist on every real Node regardless of which realm
|
|
1056
|
-
* minted the JS wrapper, so getNodeName(foreignForm) === "FORM".
|
|
1057
|
-
* - NamedNodeMap detection — compare the direct .attributes read
|
|
1058
|
-
* against the cached Element.prototype.attributes getter. Same
|
|
1059
|
-
* equality-probe pattern we use for .childNodes: if a clobbering
|
|
1060
|
-
* child shadows the named property, the two reads diverge; if not,
|
|
1061
|
-
* both return the same NamedNodeMap (same-realm OR foreign-realm —
|
|
1062
|
-
* doesn't matter, both are the canonical attributes object for the
|
|
1063
|
-
* node).
|
|
1064
|
-
*
|
|
1065
1094
|
* @param element element to check for clobbering attacks
|
|
1066
1095
|
* @return true if clobbered, false if safe
|
|
1067
1096
|
*/
|
|
@@ -1083,6 +1112,14 @@
|
|
|
1083
1112
|
// (same-realm OR foreign-realm) has both reads pointing at the same
|
|
1084
1113
|
// canonical NamedNodeMap.
|
|
1085
1114
|
element.attributes !== getAttributes(element) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function' ||
|
|
1115
|
+
// NodeType clobbering probe. Cached Node.prototype.nodeType getter
|
|
1116
|
+
// returns the integer 1 for any Element regardless of realm; direct
|
|
1117
|
+
// read on a clobbered form (e.g. <input name="nodeType">) returns
|
|
1118
|
+
// the named child element. Cheap addition — nodeType is read from
|
|
1119
|
+
// an internal slot, no serialization cost — and removes a residual
|
|
1120
|
+
// clobbering surface used by several mXSS / PI / comment branches
|
|
1121
|
+
// in _sanitizeElements that compare currentNode.nodeType directly.
|
|
1122
|
+
element.nodeType !== getNodeType(element) ||
|
|
1086
1123
|
// HTMLFormElement has [LegacyOverrideBuiltIns]: a descendant named
|
|
1087
1124
|
// "childNodes" shadows the prototype getter. Direct reads of
|
|
1088
1125
|
// form.childNodes from a clobbered form return the named child
|
|
@@ -1099,14 +1136,6 @@
|
|
|
1099
1136
|
/**
|
|
1100
1137
|
* Checks whether the given value is a DocumentFragment from any realm.
|
|
1101
1138
|
*
|
|
1102
|
-
* Realm safety (GHSA-hpcv-96wg-7vj8): the original sites used
|
|
1103
|
-
* `value instanceof DocumentFragment`, which is realm-bound — a fragment
|
|
1104
|
-
* from a foreign realm (template content or shadow root from an iframe
|
|
1105
|
-
* document) is an instance of the foreign realm's DocumentFragment, not
|
|
1106
|
-
* the parent realm's, so the check returned false and the template-
|
|
1107
|
-
* content / shadow-root recursion was silently skipped. The attacker
|
|
1108
|
-
* payload inside survived untouched.
|
|
1109
|
-
*
|
|
1110
1139
|
* The realm-independent replacement reads `nodeType` through the cached
|
|
1111
1140
|
* Node.prototype getter and compares to the DOCUMENT_FRAGMENT_NODE
|
|
1112
1141
|
* constant (11). nodeType is a numeric value resolved from the node's
|
|
@@ -1133,12 +1162,6 @@
|
|
|
1133
1162
|
* sanitize() to silently stringify them and reset IN_PLACE to false,
|
|
1134
1163
|
* returning the original node unsanitized. See GHSA-4w3q-35jp-p934.
|
|
1135
1164
|
*
|
|
1136
|
-
* Implementation: call the cached `nodeType` getter from Node.prototype
|
|
1137
|
-
* directly on the value. This bypasses any clobbered instance property
|
|
1138
|
-
* (e.g. a child element named "nodeType") and works across realms
|
|
1139
|
-
* because the WebIDL `nodeType` getter reads an internal slot that
|
|
1140
|
-
* every real Node has, regardless of which window minted it.
|
|
1141
|
-
*
|
|
1142
1165
|
* @param value object to check whether it's a DOM node
|
|
1143
1166
|
* @return true if value is a DOM node from any realm
|
|
1144
1167
|
*/
|
|
@@ -1176,7 +1199,7 @@
|
|
|
1176
1199
|
return true;
|
|
1177
1200
|
}
|
|
1178
1201
|
/* Now let's check the element's type and name */
|
|
1179
|
-
const tagName = transformCaseFunc(currentNode.nodeName);
|
|
1202
|
+
const tagName = transformCaseFunc(getNodeName ? getNodeName(currentNode) : currentNode.nodeName);
|
|
1180
1203
|
/* Execute a hook if present */
|
|
1181
1204
|
_executeHooks(hooks.uponSanitizeElement, currentNode, {
|
|
1182
1205
|
tagName,
|
|
@@ -1213,10 +1236,17 @@
|
|
|
1213
1236
|
return false;
|
|
1214
1237
|
}
|
|
1215
1238
|
}
|
|
1216
|
-
/* Keep content except for bad-listed elements
|
|
1239
|
+
/* Keep content except for bad-listed elements.
|
|
1240
|
+
Use the cached prototype getters exclusively — the previous code
|
|
1241
|
+
had `|| currentNode.parentNode` / `|| currentNode.childNodes`
|
|
1242
|
+
fallbacks, but the cached getters always return the canonical
|
|
1243
|
+
value (or null for a real parent-less node), so the fallback
|
|
1244
|
+
path was dead in safe cases and a clobbering surface in unsafe
|
|
1245
|
+
ones. Falsy cached results stay falsy; the `if (childNodes &&
|
|
1246
|
+
parentNode)` check already gates correctly. */
|
|
1217
1247
|
if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
|
|
1218
|
-
const parentNode = getParentNode(currentNode)
|
|
1219
|
-
const childNodes = getChildNodes(currentNode)
|
|
1248
|
+
const parentNode = getParentNode(currentNode);
|
|
1249
|
+
const childNodes = getChildNodes(currentNode);
|
|
1220
1250
|
if (childNodes && parentNode) {
|
|
1221
1251
|
const childCount = childNodes.length;
|
|
1222
1252
|
for (let i = childCount - 1; i >= 0; --i) {
|
|
@@ -1412,7 +1442,7 @@
|
|
|
1412
1442
|
switch (trustedTypes.getAttributeType(lcTag, lcName)) {
|
|
1413
1443
|
case 'TrustedHTML':
|
|
1414
1444
|
{
|
|
1415
|
-
value =
|
|
1445
|
+
value = _createTrustedHTML(value);
|
|
1416
1446
|
break;
|
|
1417
1447
|
}
|
|
1418
1448
|
case 'TrustedScriptURL':
|
|
@@ -1469,6 +1499,24 @@
|
|
|
1469
1499
|
if (_isDocumentFragment(shadowNode.content)) {
|
|
1470
1500
|
_sanitizeShadowDOM2(shadowNode.content);
|
|
1471
1501
|
}
|
|
1502
|
+
/* An element iterated here may itself host an attached
|
|
1503
|
+
shadow root. The default NodeIterator does not enter shadow
|
|
1504
|
+
trees, so a shadow root nested inside template.content was
|
|
1505
|
+
previously reached by no walk at all (the pre-pass at
|
|
1506
|
+
_sanitizeAttachedShadowRoots descends via childNodes, which
|
|
1507
|
+
doesn't enter template.content; the template-content recursion
|
|
1508
|
+
above iterates the content but never inspected shadowRoot).
|
|
1509
|
+
Walk it explicitly. The nodeType guard avoids reading
|
|
1510
|
+
shadowRoot off text / comment / CDATA / PI nodes that the
|
|
1511
|
+
iterator also surfaces. */
|
|
1512
|
+
const shadowNodeType = getNodeType ? getNodeType(shadowNode) : shadowNode.nodeType;
|
|
1513
|
+
if (shadowNodeType === NODE_TYPE.element) {
|
|
1514
|
+
const innerSr = getShadowRoot ? getShadowRoot(shadowNode) : shadowNode.shadowRoot;
|
|
1515
|
+
if (_isDocumentFragment(innerSr)) {
|
|
1516
|
+
_sanitizeAttachedShadowRoots2(innerSr);
|
|
1517
|
+
_sanitizeShadowDOM2(innerSr);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1472
1520
|
}
|
|
1473
1521
|
/* Execute a hook if present */
|
|
1474
1522
|
_executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
|
|
@@ -1490,17 +1538,6 @@
|
|
|
1490
1538
|
* existing _sanitizeShadowDOM template-content recursion) stay
|
|
1491
1539
|
* untouched — string-input paths are not affected.
|
|
1492
1540
|
*
|
|
1493
|
-
* DOM-Clobbering hardening: HTMLFormElement carries the WebIDL
|
|
1494
|
-
* [LegacyOverrideBuiltIns] extended attribute, so a descendant element
|
|
1495
|
-
* named `nodeType`, `shadowRoot`, or `childNodes` shadows the matching
|
|
1496
|
-
* prototype getter on the form. Reading those properties directly off
|
|
1497
|
-
* the node would let an attacker steer this walk past shadow hosts
|
|
1498
|
-
* (e.g. <input name="childNodes"> collapses the form's child list to
|
|
1499
|
-
* the input itself, so descent stops dead and any shadow root deeper
|
|
1500
|
-
* in the subtree is never sanitized). Every property access here is
|
|
1501
|
-
* therefore routed through the cached prototype getter; the form's
|
|
1502
|
-
* named-property getter cannot intercept those reads.
|
|
1503
|
-
*
|
|
1504
1541
|
* @param root the subtree root to walk for attached shadow roots
|
|
1505
1542
|
*/
|
|
1506
1543
|
const _sanitizeAttachedShadowRoots2 = function _sanitizeAttachedShadowRoots(root) {
|
|
@@ -1536,6 +1573,16 @@
|
|
|
1536
1573
|
for (const child of snapshot) {
|
|
1537
1574
|
_sanitizeAttachedShadowRoots2(child);
|
|
1538
1575
|
}
|
|
1576
|
+
/* When the root is a <template>, also descend into root.content */
|
|
1577
|
+
if (nodeType === NODE_TYPE.element) {
|
|
1578
|
+
const rootName = getNodeName ? getNodeName(root) : null;
|
|
1579
|
+
if (typeof rootName === 'string' && transformCaseFunc(rootName) === 'template') {
|
|
1580
|
+
const content = root.content;
|
|
1581
|
+
if (_isDocumentFragment(content)) {
|
|
1582
|
+
_sanitizeAttachedShadowRoots2(content);
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1539
1586
|
};
|
|
1540
1587
|
// eslint-disable-next-line complexity
|
|
1541
1588
|
DOMPurify.sanitize = function (dirty) {
|
|
@@ -1626,7 +1673,7 @@
|
|
|
1626
1673
|
if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&
|
|
1627
1674
|
// eslint-disable-next-line unicorn/prefer-includes
|
|
1628
1675
|
dirty.indexOf('<') === -1) {
|
|
1629
|
-
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ?
|
|
1676
|
+
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(dirty) : dirty;
|
|
1630
1677
|
}
|
|
1631
1678
|
/* Initialize the document to work on */
|
|
1632
1679
|
body = _initDocument(dirty);
|
|
@@ -1658,14 +1705,14 @@
|
|
|
1658
1705
|
/* If we sanitized `dirty` in-place, return it. */
|
|
1659
1706
|
if (IN_PLACE) {
|
|
1660
1707
|
if (SAFE_FOR_TEMPLATES) {
|
|
1661
|
-
|
|
1708
|
+
_scrubTemplateExpressions2(dirty);
|
|
1662
1709
|
}
|
|
1663
1710
|
return dirty;
|
|
1664
1711
|
}
|
|
1665
1712
|
/* Return sanitized string or DOM */
|
|
1666
1713
|
if (RETURN_DOM) {
|
|
1667
1714
|
if (SAFE_FOR_TEMPLATES) {
|
|
1668
|
-
|
|
1715
|
+
_scrubTemplateExpressions2(body);
|
|
1669
1716
|
}
|
|
1670
1717
|
if (RETURN_DOM_FRAGMENT) {
|
|
1671
1718
|
returnNode = createDocumentFragment.call(body.ownerDocument);
|
|
@@ -1699,7 +1746,7 @@
|
|
|
1699
1746
|
serializedHTML = stringReplace(serializedHTML, expr, ' ');
|
|
1700
1747
|
});
|
|
1701
1748
|
}
|
|
1702
|
-
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ?
|
|
1749
|
+
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(serializedHTML) : serializedHTML;
|
|
1703
1750
|
};
|
|
1704
1751
|
DOMPurify.setConfig = function () {
|
|
1705
1752
|
let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|