dompurify 3.1.0 → 3.1.2

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/dist/purify.js CHANGED
@@ -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.2 | (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.2/LICENSE */
2
2
 
3
3
  (function (global, factory) {
4
4
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
@@ -288,7 +288,7 @@
288
288
  * Version label, exposed for easier checks
289
289
  * if DOMPurify is up to date or not
290
290
  */
291
- DOMPurify.version = '3.1.0';
291
+ DOMPurify.version = '3.1.2';
292
292
 
293
293
  /**
294
294
  * Array of elements that DOMPurify removed during sanitation.
@@ -521,6 +521,9 @@
521
521
  /* Keep a reference to config to pass to hooks */
522
522
  let CONFIG = null;
523
523
 
524
+ /* Specify the maximum element nesting depth to prevent mXSS */
525
+ const MAX_NESTING_DEPTH = 255;
526
+
524
527
  /* Ideally, do not touch anything below this line */
525
528
  /* ______________________________________________ */
526
529
 
@@ -707,7 +710,7 @@
707
710
  CONFIG = cfg;
708
711
  };
709
712
  const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
710
- const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']);
713
+ const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'annotation-xml']);
711
714
 
712
715
  // Certain elements are allowed in both SVG and HTML
713
716
  // namespace. We need to specify them explicitly
@@ -931,7 +934,11 @@
931
934
  * @return {Boolean} true if clobbered, false if safe
932
935
  */
933
936
  const _isClobbered = function _isClobbered(elm) {
934
- 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');
937
+ return elm instanceof HTMLFormElement && (
938
+ // eslint-disable-next-line unicorn/no-typeof-undefined
939
+ typeof elm.__depth !== 'undefined' && typeof elm.__depth !== 'number' ||
940
+ // eslint-disable-next-line unicorn/no-typeof-undefined
941
+ 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');
935
942
  };
936
943
 
937
944
  /**
@@ -1029,7 +1036,9 @@
1029
1036
  if (childNodes && parentNode) {
1030
1037
  const childCount = childNodes.length;
1031
1038
  for (let i = childCount - 1; i >= 0; --i) {
1032
- parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
1039
+ const childClone = cloneNode(childNodes[i], true);
1040
+ childClone.__removalCount = (currentNode.__removalCount || 0) + 1;
1041
+ parentNode.insertBefore(childClone, getNextSibling(currentNode));
1033
1042
  }
1034
1043
  }
1035
1044
  }
@@ -1261,9 +1270,29 @@
1261
1270
  if (_sanitizeElements(shadowNode)) {
1262
1271
  continue;
1263
1272
  }
1273
+ const parentNode = getParentNode(shadowNode);
1274
+
1275
+ /* Set the nesting depth of an element */
1276
+ if (shadowNode.nodeType === 1) {
1277
+ if (parentNode && parentNode.__depth) {
1278
+ /*
1279
+ We want the depth of the node in the original tree, which can
1280
+ change when it's removed from its parent.
1281
+ */
1282
+ shadowNode.__depth = (shadowNode.__removalCount || 0) + parentNode.__depth + 1;
1283
+ } else {
1284
+ shadowNode.__depth = 1;
1285
+ }
1286
+ }
1287
+
1288
+ /* Remove an element if nested too deeply to avoid mXSS */
1289
+ if (shadowNode.__depth >= MAX_NESTING_DEPTH) {
1290
+ _forceRemove(shadowNode);
1291
+ }
1264
1292
 
1265
1293
  /* Deep shadow DOM detected */
1266
1294
  if (shadowNode.content instanceof DocumentFragment) {
1295
+ shadowNode.content.__depth = shadowNode.__depth;
1267
1296
  _sanitizeShadowDOM(shadowNode.content);
1268
1297
  }
1269
1298
 
@@ -1379,9 +1408,29 @@
1379
1408
  if (_sanitizeElements(currentNode)) {
1380
1409
  continue;
1381
1410
  }
1411
+ const parentNode = getParentNode(currentNode);
1412
+
1413
+ /* Set the nesting depth of an element */
1414
+ if (currentNode.nodeType === 1) {
1415
+ if (parentNode && parentNode.__depth) {
1416
+ /*
1417
+ We want the depth of the node in the original tree, which can
1418
+ change when it's removed from its parent.
1419
+ */
1420
+ currentNode.__depth = (currentNode.__removalCount || 0) + parentNode.__depth + 1;
1421
+ } else {
1422
+ currentNode.__depth = 1;
1423
+ }
1424
+ }
1425
+
1426
+ /* Remove an element if nested too deeply to avoid mXSS */
1427
+ if (currentNode.__depth >= MAX_NESTING_DEPTH) {
1428
+ _forceRemove(currentNode);
1429
+ }
1382
1430
 
1383
1431
  /* Shadow DOM detected, sanitize it */
1384
1432
  if (currentNode.content instanceof DocumentFragment) {
1433
+ currentNode.content.__depth = currentNode.__depth;
1385
1434
  _sanitizeShadowDOM(currentNode.content);
1386
1435
  }
1387
1436