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.
package/dist/purify.js CHANGED
@@ -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
  (function (global, factory) {
4
4
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
@@ -54,6 +54,7 @@
54
54
  const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
55
55
  const regExpTest = unapply(RegExp.prototype.test);
56
56
  const typeErrorCreate = unconstruct(TypeError);
57
+ const numberIsNaN = unapply(Number.isNaN);
57
58
 
58
59
  /**
59
60
  * Creates a new function that calls the given function with a specified thisArg and arguments.
@@ -237,6 +238,24 @@
237
238
  CUSTOM_ELEMENT: CUSTOM_ELEMENT
238
239
  });
239
240
 
241
+ // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
242
+ const NODE_TYPE = {
243
+ element: 1,
244
+ attribute: 2,
245
+ text: 3,
246
+ cdataSection: 4,
247
+ entityReference: 5,
248
+ // Deprecated
249
+ entityNode: 6,
250
+ // Deprecated
251
+ progressingInstruction: 7,
252
+ comment: 8,
253
+ document: 9,
254
+ documentType: 10,
255
+ documentFragment: 11,
256
+ notation: 12 // Deprecated
257
+ };
258
+
240
259
  const getGlobal = function getGlobal() {
241
260
  return typeof window === 'undefined' ? null : window;
242
261
  };
@@ -288,14 +307,14 @@
288
307
  * Version label, exposed for easier checks
289
308
  * if DOMPurify is up to date or not
290
309
  */
291
- DOMPurify.version = '3.1.1';
310
+ DOMPurify.version = '3.1.3';
292
311
 
293
312
  /**
294
313
  * Array of elements that DOMPurify removed during sanitation.
295
314
  * Empty if nothing was removed.
296
315
  */
297
316
  DOMPurify.removed = [];
298
- if (!window || !window.document || window.document.nodeType !== 9) {
317
+ if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document) {
299
318
  // Not running in a browser, provide a factory function
300
319
  // so that you can pass your own Window
301
320
  DOMPurify.isSupported = false;
@@ -710,7 +729,7 @@
710
729
  CONFIG = cfg;
711
730
  };
712
731
  const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
713
- const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']);
732
+ const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'annotation-xml']);
714
733
 
715
734
  // Certain elements are allowed in both SVG and HTML
716
735
  // namespace. We need to specify them explicitly
@@ -1006,13 +1025,13 @@
1006
1025
  }
1007
1026
 
1008
1027
  /* Remove any ocurrence of processing instructions */
1009
- if (currentNode.nodeType === 7) {
1028
+ if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
1010
1029
  _forceRemove(currentNode);
1011
1030
  return true;
1012
1031
  }
1013
1032
 
1014
1033
  /* Remove any kind of possibly harmful comments */
1015
- if (SAFE_FOR_XML && currentNode.nodeType === 8 && regExpTest(/<[/\w]/g, currentNode.data)) {
1034
+ if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\w]/g, currentNode.data)) {
1016
1035
  _forceRemove(currentNode);
1017
1036
  return true;
1018
1037
  }
@@ -1059,7 +1078,7 @@
1059
1078
  }
1060
1079
 
1061
1080
  /* Sanitize element content to be template-safe */
1062
- if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
1081
+ if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
1063
1082
  /* Get the element's text content */
1064
1083
  content = currentNode.textContent;
1065
1084
  arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
@@ -1089,7 +1108,7 @@
1089
1108
  // eslint-disable-next-line complexity
1090
1109
  const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
1091
1110
  /* Make sure attribute cannot clobber */
1092
- if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
1111
+ if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement || value === '__depth' || value === '__removalCount')) {
1093
1112
  return false;
1094
1113
  }
1095
1114
 
@@ -1193,6 +1212,12 @@
1193
1212
  continue;
1194
1213
  }
1195
1214
 
1215
+ /* Work around a security issue with comments inside attributes */
1216
+ if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title)/i, value)) {
1217
+ _removeAttribute(name, currentNode);
1218
+ continue;
1219
+ }
1220
+
1196
1221
  /* Sanitize attribute content to be template-safe */
1197
1222
  if (SAFE_FOR_TEMPLATES) {
1198
1223
  arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
@@ -1243,7 +1268,11 @@
1243
1268
  /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
1244
1269
  currentNode.setAttribute(name, value);
1245
1270
  }
1246
- arrayPop(DOMPurify.removed);
1271
+ if (_isClobbered(currentNode)) {
1272
+ _forceRemove(currentNode);
1273
+ } else {
1274
+ arrayPop(DOMPurify.removed);
1275
+ }
1247
1276
  } catch (_) {}
1248
1277
  }
1249
1278
 
@@ -1270,22 +1299,26 @@
1270
1299
  if (_sanitizeElements(shadowNode)) {
1271
1300
  continue;
1272
1301
  }
1302
+ const parentNode = getParentNode(shadowNode);
1273
1303
 
1274
1304
  /* Set the nesting depth of an element */
1275
- if (shadowNode.nodeType === 1) {
1276
- if (shadowNode.parentNode && shadowNode.parentNode.__depth) {
1305
+ if (shadowNode.nodeType === NODE_TYPE.element) {
1306
+ if (parentNode && parentNode.__depth) {
1277
1307
  /*
1278
1308
  We want the depth of the node in the original tree, which can
1279
1309
  change when it's removed from its parent.
1280
1310
  */
1281
- shadowNode.__depth = (shadowNode.__removalCount || 0) + shadowNode.parentNode.__depth + 1;
1311
+ shadowNode.__depth = (shadowNode.__removalCount || 0) + parentNode.__depth + 1;
1282
1312
  } else {
1283
1313
  shadowNode.__depth = 1;
1284
1314
  }
1285
1315
  }
1286
1316
 
1287
- /* Remove an element if nested too deeply to avoid mXSS */
1288
- if (shadowNode.__depth >= MAX_NESTING_DEPTH) {
1317
+ /*
1318
+ * Remove an element if nested too deeply to avoid mXSS
1319
+ * or if the __depth might have been tampered with
1320
+ */
1321
+ if (shadowNode.__depth >= MAX_NESTING_DEPTH || shadowNode.__depth < 0 || numberIsNaN(shadowNode.__depth)) {
1289
1322
  _forceRemove(shadowNode);
1290
1323
  }
1291
1324
 
@@ -1367,7 +1400,7 @@
1367
1400
  elements being stripped by the parser */
1368
1401
  body = _initDocument('<!---->');
1369
1402
  importedNode = body.ownerDocument.importNode(dirty, true);
1370
- if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
1403
+ if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === 'BODY') {
1371
1404
  /* Node is already a body, use as is */
1372
1405
  body = importedNode;
1373
1406
  } else if (importedNode.nodeName === 'HTML') {
@@ -1407,22 +1440,26 @@
1407
1440
  if (_sanitizeElements(currentNode)) {
1408
1441
  continue;
1409
1442
  }
1443
+ const parentNode = getParentNode(currentNode);
1410
1444
 
1411
1445
  /* Set the nesting depth of an element */
1412
- if (currentNode.nodeType === 1) {
1413
- if (currentNode.parentNode && currentNode.parentNode.__depth) {
1446
+ if (currentNode.nodeType === NODE_TYPE.element) {
1447
+ if (parentNode && parentNode.__depth) {
1414
1448
  /*
1415
1449
  We want the depth of the node in the original tree, which can
1416
1450
  change when it's removed from its parent.
1417
1451
  */
1418
- currentNode.__depth = (currentNode.__removalCount || 0) + currentNode.parentNode.__depth + 1;
1452
+ currentNode.__depth = (currentNode.__removalCount || 0) + parentNode.__depth + 1;
1419
1453
  } else {
1420
1454
  currentNode.__depth = 1;
1421
1455
  }
1422
1456
  }
1423
1457
 
1424
- /* Remove an element if nested too deeply to avoid mXSS */
1425
- if (currentNode.__depth >= MAX_NESTING_DEPTH) {
1458
+ /*
1459
+ * Remove an element if nested too deeply to avoid mXSS
1460
+ * or if the __depth might have been tampered with
1461
+ */
1462
+ if (currentNode.__depth >= MAX_NESTING_DEPTH || currentNode.__depth < 0 || numberIsNaN(currentNode.__depth)) {
1426
1463
  _forceRemove(currentNode);
1427
1464
  }
1428
1465