dompurify 2.3.8 → 2.3.11

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 2.3.8 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/2.3.8/LICENSE */
1
+ /*! @license DOMPurify 2.3.11 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/2.3.11/LICENSE */
2
2
 
3
3
  (function (global, factory) {
4
4
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
@@ -155,7 +155,9 @@
155
155
  }
156
156
  /* Add properties to a lookup table */
157
157
 
158
- function addToSet(set, array) {
158
+ function addToSet(set, array, transformCaseFunc) {
159
+ transformCaseFunc = transformCaseFunc ? transformCaseFunc : stringToLowerCase;
160
+
159
161
  if (setPrototypeOf) {
160
162
  // Make 'in' and truthy checks like Boolean(set.constructor)
161
163
  // independent of any properties defined on Object.prototype.
@@ -169,7 +171,7 @@
169
171
  var element = array[l];
170
172
 
171
173
  if (typeof element === 'string') {
172
- var lcElement = stringToLowerCase(element);
174
+ var lcElement = transformCaseFunc(element);
173
175
 
174
176
  if (lcElement !== element) {
175
177
  // Config presets (e.g. tags.js, attrs.js) are immutable.
@@ -298,6 +300,9 @@
298
300
  return trustedTypes.createPolicy(policyName, {
299
301
  createHTML: function createHTML(html) {
300
302
  return html;
303
+ },
304
+ createScriptURL: function createScriptURL(scriptUrl) {
305
+ return scriptUrl;
301
306
  }
302
307
  });
303
308
  } catch (_) {
@@ -321,7 +326,7 @@
321
326
  */
322
327
 
323
328
 
324
- DOMPurify.version = '2.3.8';
329
+ DOMPurify.version = '2.3.11';
325
330
  /**
326
331
  * Array of elements that DOMPurify removed during sanitation.
327
332
  * Empty if nothing was removed.
@@ -479,9 +484,27 @@
479
484
  * case Trusted Types are not supported */
480
485
 
481
486
  var RETURN_TRUSTED_TYPE = false;
482
- /* Output should be free from DOM clobbering attacks? */
487
+ /* Output should be free from DOM clobbering attacks?
488
+ * This sanitizes markups named with colliding, clobberable built-in DOM APIs.
489
+ */
483
490
 
484
491
  var SANITIZE_DOM = true;
492
+ /* Achieve full DOM Clobbering protection by isolating the namespace of named
493
+ * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
494
+ *
495
+ * HTML/DOM spec rules that enable DOM Clobbering:
496
+ * - Named Access on Window (§7.3.3)
497
+ * - DOM Tree Accessors (§3.1.5)
498
+ * - Form Element Parent-Child Relations (§4.10.3)
499
+ * - Iframe srcdoc / Nested WindowProxies (§4.8.5)
500
+ * - HTMLCollection (§4.2.10.2)
501
+ *
502
+ * Namespace isolation is implemented by prefixing `id` and `name` attributes
503
+ * with a constant string, i.e., `user-content-`
504
+ */
505
+
506
+ var SANITIZE_NAMED_PROPS = false;
507
+ var SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
485
508
  /* Keep element content when removing element? */
486
509
 
487
510
  var KEEP_CONTENT = true;
@@ -551,15 +574,29 @@
551
574
 
552
575
 
553
576
  cfg = clone(cfg);
577
+ PARSER_MEDIA_TYPE = // eslint-disable-next-line unicorn/prefer-includes
578
+ SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE; // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
579
+
580
+ transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? function (x) {
581
+ return x;
582
+ } : stringToLowerCase;
554
583
  /* Set configuration parameters */
555
584
 
556
- ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS) : DEFAULT_ALLOWED_TAGS;
557
- ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR;
558
- URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR) : DEFAULT_URI_SAFE_ATTRIBUTES;
559
- DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS) : DEFAULT_DATA_URI_TAGS;
560
- FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS) : DEFAULT_FORBID_CONTENTS;
561
- FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS) : {};
562
- FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR) : {};
585
+ ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
586
+ ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
587
+ URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), // eslint-disable-line indent
588
+ cfg.ADD_URI_SAFE_ATTR, // eslint-disable-line indent
589
+ transformCaseFunc // eslint-disable-line indent
590
+ ) // eslint-disable-line indent
591
+ : DEFAULT_URI_SAFE_ATTRIBUTES;
592
+ DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), // eslint-disable-line indent
593
+ cfg.ADD_DATA_URI_TAGS, // eslint-disable-line indent
594
+ transformCaseFunc // eslint-disable-line indent
595
+ ) // eslint-disable-line indent
596
+ : DEFAULT_DATA_URI_TAGS;
597
+ FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
598
+ FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
599
+ FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
563
600
  USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
564
601
  ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
565
602
 
@@ -581,6 +618,8 @@
581
618
 
582
619
  SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
583
620
 
621
+ SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
622
+
584
623
  KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
585
624
 
586
625
  IN_PLACE = cfg.IN_PLACE || false; // Default false
@@ -600,13 +639,6 @@
600
639
  CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
601
640
  }
602
641
 
603
- PARSER_MEDIA_TYPE = // eslint-disable-next-line unicorn/prefer-includes
604
- SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE; // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
605
-
606
- transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? function (x) {
607
- return x;
608
- } : stringToLowerCase;
609
-
610
642
  if (SAFE_FOR_TEMPLATES) {
611
643
  ALLOW_DATA_ATTR = false;
612
644
  }
@@ -652,7 +684,7 @@
652
684
  ALLOWED_TAGS = clone(ALLOWED_TAGS);
653
685
  }
654
686
 
655
- addToSet(ALLOWED_TAGS, cfg.ADD_TAGS);
687
+ addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
656
688
  }
657
689
 
658
690
  if (cfg.ADD_ATTR) {
@@ -660,11 +692,11 @@
660
692
  ALLOWED_ATTR = clone(ALLOWED_ATTR);
661
693
  }
662
694
 
663
- addToSet(ALLOWED_ATTR, cfg.ADD_ATTR);
695
+ addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
664
696
  }
665
697
 
666
698
  if (cfg.ADD_URI_SAFE_ATTR) {
667
- addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR);
699
+ addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
668
700
  }
669
701
 
670
702
  if (cfg.FORBID_CONTENTS) {
@@ -672,7 +704,7 @@
672
704
  FORBID_CONTENTS = clone(FORBID_CONTENTS);
673
705
  }
674
706
 
675
- addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS);
707
+ addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
676
708
  }
677
709
  /* Add #text in case KEEP_CONTENT is set to true */
678
710
 
@@ -1244,6 +1276,34 @@
1244
1276
  if (!_isValidAttribute(lcTag, lcName, value)) {
1245
1277
  continue;
1246
1278
  }
1279
+ /* Full DOM Clobbering protection via namespace isolation,
1280
+ * Prefix id and name attributes with `user-content-`
1281
+ */
1282
+
1283
+
1284
+ if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
1285
+ // Remove the attribute with this value
1286
+ _removeAttribute(name, currentNode); // Prefix the value and later re-create the attribute with the sanitized value
1287
+
1288
+
1289
+ value = SANITIZE_NAMED_PROPS_PREFIX + value;
1290
+ }
1291
+ /* Handle attributes that require Trusted Types */
1292
+
1293
+
1294
+ if (trustedTypesPolicy && _typeof(trustedTypes) === 'object' && typeof trustedTypes.getAttributeType === 'function') {
1295
+ if (namespaceURI) ; else {
1296
+ switch (trustedTypes.getAttributeType(lcTag, lcName)) {
1297
+ case 'TrustedHTML':
1298
+ value = trustedTypesPolicy.createHTML(value);
1299
+ break;
1300
+
1301
+ case 'TrustedScriptURL':
1302
+ value = trustedTypesPolicy.createScriptURL(value);
1303
+ break;
1304
+ }
1305
+ }
1306
+ }
1247
1307
  /* Handle invalid data-* attribute set by try-catching it */
1248
1308
 
1249
1309