dompurify 3.1.0 → 3.1.1

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.
@@ -1,4 +1,4 @@
1
- /*! @license DOMPurify 3.1.0 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.0/LICENSE */
1
+ /*! @license DOMPurify 3.1.1 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.1/LICENSE */
2
2
 
3
3
  const {
4
4
  entries,
@@ -282,7 +282,7 @@ function createDOMPurify() {
282
282
  * Version label, exposed for easier checks
283
283
  * if DOMPurify is up to date or not
284
284
  */
285
- DOMPurify.version = '3.1.0';
285
+ DOMPurify.version = '3.1.1';
286
286
 
287
287
  /**
288
288
  * Array of elements that DOMPurify removed during sanitation.
@@ -515,6 +515,9 @@ function createDOMPurify() {
515
515
  /* Keep a reference to config to pass to hooks */
516
516
  let CONFIG = null;
517
517
 
518
+ /* Specify the maximum element nesting depth to prevent mXSS */
519
+ const MAX_NESTING_DEPTH = 255;
520
+
518
521
  /* Ideally, do not touch anything below this line */
519
522
  /* ______________________________________________ */
520
523
 
@@ -925,7 +928,11 @@ function createDOMPurify() {
925
928
  * @return {Boolean} true if clobbered, false if safe
926
929
  */
927
930
  const _isClobbered = function _isClobbered(elm) {
928
- return elm instanceof HTMLFormElement && (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function' || typeof elm.hasChildNodes !== 'function');
931
+ return elm instanceof HTMLFormElement && (
932
+ // eslint-disable-next-line unicorn/no-typeof-undefined
933
+ typeof elm.__depth !== 'undefined' && typeof elm.__depth !== 'number' ||
934
+ // eslint-disable-next-line unicorn/no-typeof-undefined
935
+ typeof elm.__removalCount !== 'undefined' && typeof elm.__removalCount !== 'number' || typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function' || typeof elm.hasChildNodes !== 'function');
929
936
  };
930
937
 
931
938
  /**
@@ -1023,7 +1030,9 @@ function createDOMPurify() {
1023
1030
  if (childNodes && parentNode) {
1024
1031
  const childCount = childNodes.length;
1025
1032
  for (let i = childCount - 1; i >= 0; --i) {
1026
- parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
1033
+ const childClone = cloneNode(childNodes[i], true);
1034
+ childClone.__removalCount = (currentNode.__removalCount || 0) + 1;
1035
+ parentNode.insertBefore(childClone, getNextSibling(currentNode));
1027
1036
  }
1028
1037
  }
1029
1038
  }
@@ -1256,8 +1265,27 @@ function createDOMPurify() {
1256
1265
  continue;
1257
1266
  }
1258
1267
 
1268
+ /* Set the nesting depth of an element */
1269
+ if (shadowNode.nodeType === 1) {
1270
+ if (shadowNode.parentNode && shadowNode.parentNode.__depth) {
1271
+ /*
1272
+ We want the depth of the node in the original tree, which can
1273
+ change when it's removed from its parent.
1274
+ */
1275
+ shadowNode.__depth = (shadowNode.__removalCount || 0) + shadowNode.parentNode.__depth + 1;
1276
+ } else {
1277
+ shadowNode.__depth = 1;
1278
+ }
1279
+ }
1280
+
1281
+ /* Remove an element if nested too deeply to avoid mXSS */
1282
+ if (shadowNode.__depth >= MAX_NESTING_DEPTH) {
1283
+ _forceRemove(shadowNode);
1284
+ }
1285
+
1259
1286
  /* Deep shadow DOM detected */
1260
1287
  if (shadowNode.content instanceof DocumentFragment) {
1288
+ shadowNode.content.__depth = shadowNode.__depth;
1261
1289
  _sanitizeShadowDOM(shadowNode.content);
1262
1290
  }
1263
1291
 
@@ -1374,8 +1402,27 @@ function createDOMPurify() {
1374
1402
  continue;
1375
1403
  }
1376
1404
 
1405
+ /* Set the nesting depth of an element */
1406
+ if (currentNode.nodeType === 1) {
1407
+ if (currentNode.parentNode && currentNode.parentNode.__depth) {
1408
+ /*
1409
+ We want the depth of the node in the original tree, which can
1410
+ change when it's removed from its parent.
1411
+ */
1412
+ currentNode.__depth = (currentNode.__removalCount || 0) + currentNode.parentNode.__depth + 1;
1413
+ } else {
1414
+ currentNode.__depth = 1;
1415
+ }
1416
+ }
1417
+
1418
+ /* Remove an element if nested too deeply to avoid mXSS */
1419
+ if (currentNode.__depth >= MAX_NESTING_DEPTH) {
1420
+ _forceRemove(currentNode);
1421
+ }
1422
+
1377
1423
  /* Shadow DOM detected, sanitize it */
1378
1424
  if (currentNode.content instanceof DocumentFragment) {
1425
+ currentNode.content.__depth = currentNode.__depth;
1379
1426
  _sanitizeShadowDOM(currentNode.content);
1380
1427
  }
1381
1428