dompurify 3.1.1 → 3.1.3

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.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 */
1
+ /*! @license DOMPurify 3.1.3 | (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.3/LICENSE */
2
2
 
3
3
  const {
4
4
  entries,
@@ -48,6 +48,7 @@ const stringTrim = unapply(String.prototype.trim);
48
48
  const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
49
49
  const regExpTest = unapply(RegExp.prototype.test);
50
50
  const typeErrorCreate = unconstruct(TypeError);
51
+ const numberIsNaN = unapply(Number.isNaN);
51
52
 
52
53
  /**
53
54
  * Creates a new function that calls the given function with a specified thisArg and arguments.
@@ -231,6 +232,24 @@ var EXPRESSIONS = /*#__PURE__*/Object.freeze({
231
232
  CUSTOM_ELEMENT: CUSTOM_ELEMENT
232
233
  });
233
234
 
235
+ // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
236
+ const NODE_TYPE = {
237
+ element: 1,
238
+ attribute: 2,
239
+ text: 3,
240
+ cdataSection: 4,
241
+ entityReference: 5,
242
+ // Deprecated
243
+ entityNode: 6,
244
+ // Deprecated
245
+ progressingInstruction: 7,
246
+ comment: 8,
247
+ document: 9,
248
+ documentType: 10,
249
+ documentFragment: 11,
250
+ notation: 12 // Deprecated
251
+ };
252
+
234
253
  const getGlobal = function getGlobal() {
235
254
  return typeof window === 'undefined' ? null : window;
236
255
  };
@@ -282,14 +301,14 @@ function createDOMPurify() {
282
301
  * Version label, exposed for easier checks
283
302
  * if DOMPurify is up to date or not
284
303
  */
285
- DOMPurify.version = '3.1.1';
304
+ DOMPurify.version = '3.1.3';
286
305
 
287
306
  /**
288
307
  * Array of elements that DOMPurify removed during sanitation.
289
308
  * Empty if nothing was removed.
290
309
  */
291
310
  DOMPurify.removed = [];
292
- if (!window || !window.document || window.document.nodeType !== 9) {
311
+ if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document) {
293
312
  // Not running in a browser, provide a factory function
294
313
  // so that you can pass your own Window
295
314
  DOMPurify.isSupported = false;
@@ -704,7 +723,7 @@ function createDOMPurify() {
704
723
  CONFIG = cfg;
705
724
  };
706
725
  const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
707
- const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']);
726
+ const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'annotation-xml']);
708
727
 
709
728
  // Certain elements are allowed in both SVG and HTML
710
729
  // namespace. We need to specify them explicitly
@@ -1000,13 +1019,13 @@ function createDOMPurify() {
1000
1019
  }
1001
1020
 
1002
1021
  /* Remove any ocurrence of processing instructions */
1003
- if (currentNode.nodeType === 7) {
1022
+ if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
1004
1023
  _forceRemove(currentNode);
1005
1024
  return true;
1006
1025
  }
1007
1026
 
1008
1027
  /* Remove any kind of possibly harmful comments */
1009
- if (SAFE_FOR_XML && currentNode.nodeType === 8 && regExpTest(/<[/\w]/g, currentNode.data)) {
1028
+ if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\w]/g, currentNode.data)) {
1010
1029
  _forceRemove(currentNode);
1011
1030
  return true;
1012
1031
  }
@@ -1053,7 +1072,7 @@ function createDOMPurify() {
1053
1072
  }
1054
1073
 
1055
1074
  /* Sanitize element content to be template-safe */
1056
- if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
1075
+ if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
1057
1076
  /* Get the element's text content */
1058
1077
  content = currentNode.textContent;
1059
1078
  arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
@@ -1083,7 +1102,7 @@ function createDOMPurify() {
1083
1102
  // eslint-disable-next-line complexity
1084
1103
  const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
1085
1104
  /* Make sure attribute cannot clobber */
1086
- if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
1105
+ if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement || value === '__depth' || value === '__removalCount')) {
1087
1106
  return false;
1088
1107
  }
1089
1108
 
@@ -1187,6 +1206,12 @@ function createDOMPurify() {
1187
1206
  continue;
1188
1207
  }
1189
1208
 
1209
+ /* Work around a security issue with comments inside attributes */
1210
+ if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title)/i, value)) {
1211
+ _removeAttribute(name, currentNode);
1212
+ continue;
1213
+ }
1214
+
1190
1215
  /* Sanitize attribute content to be template-safe */
1191
1216
  if (SAFE_FOR_TEMPLATES) {
1192
1217
  arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
@@ -1237,7 +1262,11 @@ function createDOMPurify() {
1237
1262
  /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
1238
1263
  currentNode.setAttribute(name, value);
1239
1264
  }
1240
- arrayPop(DOMPurify.removed);
1265
+ if (_isClobbered(currentNode)) {
1266
+ _forceRemove(currentNode);
1267
+ } else {
1268
+ arrayPop(DOMPurify.removed);
1269
+ }
1241
1270
  } catch (_) {}
1242
1271
  }
1243
1272
 
@@ -1264,22 +1293,26 @@ function createDOMPurify() {
1264
1293
  if (_sanitizeElements(shadowNode)) {
1265
1294
  continue;
1266
1295
  }
1296
+ const parentNode = getParentNode(shadowNode);
1267
1297
 
1268
1298
  /* Set the nesting depth of an element */
1269
- if (shadowNode.nodeType === 1) {
1270
- if (shadowNode.parentNode && shadowNode.parentNode.__depth) {
1299
+ if (shadowNode.nodeType === NODE_TYPE.element) {
1300
+ if (parentNode && parentNode.__depth) {
1271
1301
  /*
1272
1302
  We want the depth of the node in the original tree, which can
1273
1303
  change when it's removed from its parent.
1274
1304
  */
1275
- shadowNode.__depth = (shadowNode.__removalCount || 0) + shadowNode.parentNode.__depth + 1;
1305
+ shadowNode.__depth = (shadowNode.__removalCount || 0) + parentNode.__depth + 1;
1276
1306
  } else {
1277
1307
  shadowNode.__depth = 1;
1278
1308
  }
1279
1309
  }
1280
1310
 
1281
- /* Remove an element if nested too deeply to avoid mXSS */
1282
- if (shadowNode.__depth >= MAX_NESTING_DEPTH) {
1311
+ /*
1312
+ * Remove an element if nested too deeply to avoid mXSS
1313
+ * or if the __depth might have been tampered with
1314
+ */
1315
+ if (shadowNode.__depth >= MAX_NESTING_DEPTH || shadowNode.__depth < 0 || numberIsNaN(shadowNode.__depth)) {
1283
1316
  _forceRemove(shadowNode);
1284
1317
  }
1285
1318
 
@@ -1361,7 +1394,7 @@ function createDOMPurify() {
1361
1394
  elements being stripped by the parser */
1362
1395
  body = _initDocument('<!---->');
1363
1396
  importedNode = body.ownerDocument.importNode(dirty, true);
1364
- if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
1397
+ if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === 'BODY') {
1365
1398
  /* Node is already a body, use as is */
1366
1399
  body = importedNode;
1367
1400
  } else if (importedNode.nodeName === 'HTML') {
@@ -1401,22 +1434,26 @@ function createDOMPurify() {
1401
1434
  if (_sanitizeElements(currentNode)) {
1402
1435
  continue;
1403
1436
  }
1437
+ const parentNode = getParentNode(currentNode);
1404
1438
 
1405
1439
  /* Set the nesting depth of an element */
1406
- if (currentNode.nodeType === 1) {
1407
- if (currentNode.parentNode && currentNode.parentNode.__depth) {
1440
+ if (currentNode.nodeType === NODE_TYPE.element) {
1441
+ if (parentNode && parentNode.__depth) {
1408
1442
  /*
1409
1443
  We want the depth of the node in the original tree, which can
1410
1444
  change when it's removed from its parent.
1411
1445
  */
1412
- currentNode.__depth = (currentNode.__removalCount || 0) + currentNode.parentNode.__depth + 1;
1446
+ currentNode.__depth = (currentNode.__removalCount || 0) + parentNode.__depth + 1;
1413
1447
  } else {
1414
1448
  currentNode.__depth = 1;
1415
1449
  }
1416
1450
  }
1417
1451
 
1418
- /* Remove an element if nested too deeply to avoid mXSS */
1419
- if (currentNode.__depth >= MAX_NESTING_DEPTH) {
1452
+ /*
1453
+ * Remove an element if nested too deeply to avoid mXSS
1454
+ * or if the __depth might have been tampered with
1455
+ */
1456
+ if (currentNode.__depth >= MAX_NESTING_DEPTH || currentNode.__depth < 0 || numberIsNaN(currentNode.__depth)) {
1420
1457
  _forceRemove(currentNode);
1421
1458
  }
1422
1459