dompurify 3.1.2 → 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.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 */
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.2';
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;
@@ -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
 
@@ -1273,7 +1302,7 @@
1273
1302
  const parentNode = getParentNode(shadowNode);
1274
1303
 
1275
1304
  /* Set the nesting depth of an element */
1276
- if (shadowNode.nodeType === 1) {
1305
+ if (shadowNode.nodeType === NODE_TYPE.element) {
1277
1306
  if (parentNode && parentNode.__depth) {
1278
1307
  /*
1279
1308
  We want the depth of the node in the original tree, which can
@@ -1285,8 +1314,11 @@
1285
1314
  }
1286
1315
  }
1287
1316
 
1288
- /* Remove an element if nested too deeply to avoid mXSS */
1289
- 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)) {
1290
1322
  _forceRemove(shadowNode);
1291
1323
  }
1292
1324
 
@@ -1368,7 +1400,7 @@
1368
1400
  elements being stripped by the parser */
1369
1401
  body = _initDocument('<!---->');
1370
1402
  importedNode = body.ownerDocument.importNode(dirty, true);
1371
- if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
1403
+ if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === 'BODY') {
1372
1404
  /* Node is already a body, use as is */
1373
1405
  body = importedNode;
1374
1406
  } else if (importedNode.nodeName === 'HTML') {
@@ -1411,7 +1443,7 @@
1411
1443
  const parentNode = getParentNode(currentNode);
1412
1444
 
1413
1445
  /* Set the nesting depth of an element */
1414
- if (currentNode.nodeType === 1) {
1446
+ if (currentNode.nodeType === NODE_TYPE.element) {
1415
1447
  if (parentNode && parentNode.__depth) {
1416
1448
  /*
1417
1449
  We want the depth of the node in the original tree, which can
@@ -1423,8 +1455,11 @@
1423
1455
  }
1424
1456
  }
1425
1457
 
1426
- /* Remove an element if nested too deeply to avoid mXSS */
1427
- 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)) {
1428
1463
  _forceRemove(currentNode);
1429
1464
  }
1430
1465