dompurify 2.2.9 → 2.3.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/README.md CHANGED
@@ -6,11 +6,11 @@
6
6
 
7
7
  DOMPurify is a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG.
8
8
 
9
- It's also very simple to use and get started with. DOMPurify was [started in February 2014](https://github.com/cure53/DOMPurify/commit/a630922616927373485e0e787ab19e73e3691b2b) and, meanwhile, has reached version 2.2.9.
9
+ It's also very simple to use and get started with. DOMPurify was [started in February 2014](https://github.com/cure53/DOMPurify/commit/a630922616927373485e0e787ab19e73e3691b2b) and, meanwhile, has reached version 2.3.3.
10
10
 
11
11
  DOMPurify is written in JavaScript and works in all modern browsers (Safari (10+), Opera (15+), Internet Explorer (10+), Edge, Firefox and Chrome - as well as almost anything else using Blink or WebKit). It doesn't break on MSIE6 or other legacy browsers. It either uses [a fall-back](#what-about-older-browsers-like-msie8) or simply does nothing.
12
12
 
13
- Our automated tests cover [15 different browsers](https://github.com/cure53/DOMPurify/blob/main/test/karma.custom-launchers.config.js#L5) right now, more to come. We also cover Node.js v14.15.1, v15.4.0, running DOMPurify on [jsdom](https://github.com/tmpvar/jsdom). Older Node.js versions are known to work as well.
13
+ Our automated tests cover [17 different browsers](https://github.com/cure53/DOMPurify/blob/main/test/karma.custom-launchers.config.js#L5) right now, more to come. We also cover Node.js v14.15.1, v15.4.0, running DOMPurify on [jsdom](https://github.com/tmpvar/jsdom). Older Node.js versions are known to work as well.
14
14
 
15
15
  DOMPurify is written by security people who have vast background in web attacks and XSS. Fear not. For more details please also read about our [Security Goals & Threat Model](https://github.com/cure53/DOMPurify/wiki/Security-Goals-&-Threat-Model). Please, read it. Like, really.
16
16
 
@@ -246,6 +246,9 @@ var clean = DOMPurify.sanitize(dirty, {KEEP_CONTENT: false});
246
246
  // glue elements like style, script or others to document.body and prevent unintuitive browser behavior in several edge-cases (default is false)
247
247
  var clean = DOMPurify.sanitize(dirty, {FORCE_BODY: true});
248
248
 
249
+ // change the parser type so sanitized data is treated as XML and not as HTML, which is the default
250
+ var clean = DOMPurify.sanitize(dirty, {PARSER_MEDIA_TYPE: 'application/xhtml+xml'});
251
+
249
252
  /**
250
253
  * Influence where we sanitize
251
254
  */
@@ -337,7 +340,7 @@ Feature releases will not be announced to this list.
337
340
 
338
341
  Many people helped and help DOMPurify become what it is and need to be acknowledged here!
339
342
 
340
- [granlem 💸](https://twitter.com/MaximeVeit), [oreoshake 💸](https://github.com/oreoshake), [dcramer 💸](https://github.com/dcramer),[tdeekens ❤️](https://github.com/tdeekens), [peernohell ❤️](https://github.com/peernohell), [NateScarlet](https://github.com/NateScarlet), [neilj](https://github.com/neilj), [fhemberger](https://github.com/fhemberger), [Joris-van-der-Wel](https://github.com/Joris-van-der-Wel), [ydaniv](https://github.com/ydaniv), [terjanq](https://twitter.com/terjanq), [filedescriptor](https://github.com/filedescriptor), [ConradIrwin](https://github.com/ConradIrwin), [gibson042](https://github.com/gibson042), [choumx](https://github.com/choumx), [0xSobky](https://github.com/0xSobky), [styfle](https://github.com/styfle), [koto](https://github.com/koto), [tlau88](https://github.com/tlau88), [strugee](https://github.com/strugee), [oparoz](https://github.com/oparoz), [mathiasbynens](https://github.com/mathiasbynens), [edg2s](https://github.com/edg2s), [dnkolegov](https://github.com/dnkolegov), [dhardtke](https://github.com/dhardtke), [wirehead](https://github.com/wirehead), [thorn0](https://github.com/thorn0), [styu](https://github.com/styu), [mozfreddyb](https://github.com/mozfreddyb), [mikesamuel](https://github.com/mikesamuel), [jorangreef](https://github.com/jorangreef), [jimmyhchan](https://github.com/jimmyhchan), [jameydeorio](https://github.com/jameydeorio), [jameskraus](https://github.com/jameskraus), [hyderali](https://github.com/hyderali), [hansottowirtz](https://github.com/hansottowirtz), [hackvertor](https://github.com/hackvertor), [freddyb](https://github.com/freddyb), [flavorjones](https://github.com/flavorjones), [djfarrelly](https://github.com/djfarrelly), [devd](https://github.com/devd), [camerondunford](https://github.com/camerondunford), [buu700](https://github.com/buu700), [buildog](https://github.com/buildog), [alabiaga](https://github.com/alabiaga), [Vector919](https://github.com/Vector919), [Robbert](https://github.com/Robbert), [GreLI](https://github.com/GreLI), [FuzzySockets](https://github.com/FuzzySockets), [ArtemBernatskyy](https://github.com/ArtemBernatskyy), [@garethheyes](https://twitter.com/garethheyes), [@shafigullin](https://twitter.com/shafigullin), [@mmrupp](https://twitter.com/mmrupp), [@irsdl](https://twitter.com/irsdl),[ShikariSenpai](https://github.com/ShikariSenpai), [ansjdnakjdnajkd](https://github.com/ansjdnakjdnajkd), [@asutherland](https://twitter.com/asutherland), [@mathias](https://twitter.com/mathias), [@cgvwzq](https://twitter.com/cgvwzq), [@robbertatwork](https://twitter.com/robbertatwork), [@giutro](https://twitter.com/giutro), [@CmdEngineer_](https://twitter.com/CmdEngineer_), [@avr4mit](https://twitter.com/avr4mit) and especially [@securitymb ❤️](https://twitter.com/securitymb) & [@masatokinugawa ❤️](https://twitter.com/masatokinugawa)
343
+ [GrantGryczan 💸](https://github.com/GrantGryczan), [lowdefy 💸](https://twitter.com/lowdefy), [granlem 💸](https://twitter.com/MaximeVeit), [oreoshake 💸](https://github.com/oreoshake), [dcramer 💸](https://github.com/dcramer),[tdeekens ❤️](https://github.com/tdeekens), [peernohell ❤️](https://github.com/peernohell), [NateScarlet](https://github.com/NateScarlet), [neilj](https://github.com/neilj), [fhemberger](https://github.com/fhemberger), [Joris-van-der-Wel](https://github.com/Joris-van-der-Wel), [ydaniv](https://github.com/ydaniv), [terjanq](https://twitter.com/terjanq), [filedescriptor](https://github.com/filedescriptor), [ConradIrwin](https://github.com/ConradIrwin), [gibson042](https://github.com/gibson042), [choumx](https://github.com/choumx), [0xSobky](https://github.com/0xSobky), [styfle](https://github.com/styfle), [koto](https://github.com/koto), [tlau88](https://github.com/tlau88), [strugee](https://github.com/strugee), [oparoz](https://github.com/oparoz), [mathiasbynens](https://github.com/mathiasbynens), [edg2s](https://github.com/edg2s), [dnkolegov](https://github.com/dnkolegov), [dhardtke](https://github.com/dhardtke), [wirehead](https://github.com/wirehead), [thorn0](https://github.com/thorn0), [styu](https://github.com/styu), [mozfreddyb](https://github.com/mozfreddyb), [mikesamuel](https://github.com/mikesamuel), [jorangreef](https://github.com/jorangreef), [jimmyhchan](https://github.com/jimmyhchan), [jameydeorio](https://github.com/jameydeorio), [jameskraus](https://github.com/jameskraus), [hyderali](https://github.com/hyderali), [hansottowirtz](https://github.com/hansottowirtz), [hackvertor](https://github.com/hackvertor), [freddyb](https://github.com/freddyb), [flavorjones](https://github.com/flavorjones), [djfarrelly](https://github.com/djfarrelly), [devd](https://github.com/devd), [camerondunford](https://github.com/camerondunford), [buu700](https://github.com/buu700), [buildog](https://github.com/buildog), [alabiaga](https://github.com/alabiaga), [Vector919](https://github.com/Vector919), [Robbert](https://github.com/Robbert), [GreLI](https://github.com/GreLI), [FuzzySockets](https://github.com/FuzzySockets), [ArtemBernatskyy](https://github.com/ArtemBernatskyy), [@garethheyes](https://twitter.com/garethheyes), [@shafigullin](https://twitter.com/shafigullin), [@mmrupp](https://twitter.com/mmrupp), [@irsdl](https://twitter.com/irsdl),[ShikariSenpai](https://github.com/ShikariSenpai), [ansjdnakjdnajkd](https://github.com/ansjdnakjdnajkd), [@asutherland](https://twitter.com/asutherland), [@mathias](https://twitter.com/mathias), [@cgvwzq](https://twitter.com/cgvwzq), [@robbertatwork](https://twitter.com/robbertatwork), [@giutro](https://twitter.com/giutro), [@CmdEngineer_](https://twitter.com/CmdEngineer_), [@avr4mit](https://twitter.com/avr4mit) and especially [@securitymb ❤️](https://twitter.com/securitymb) & [@masatokinugawa ❤️](https://twitter.com/masatokinugawa)
341
344
 
342
345
  ## Testing powered by
343
346
  <a target="_blank" href="https://www.browserstack.com/"><img width="200" src="https://www.browserstack.com/images/layout/browserstack-logo-600x315.png"></a><br>
@@ -1,4 +1,4 @@
1
- /*! @license DOMPurify | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/2.2.2/LICENSE */
1
+ /*! @license DOMPurify 2.3.3 | (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.3/LICENSE */
2
2
 
3
3
  'use strict';
4
4
 
@@ -245,7 +245,7 @@ function createDOMPurify() {
245
245
  * Version label, exposed for easier checks
246
246
  * if DOMPurify is up to date or not
247
247
  */
248
- DOMPurify.version = '2.2.9';
248
+ DOMPurify.version = '2.3.3';
249
249
 
250
250
  /**
251
251
  * Array of elements that DOMPurify removed during sanitation.
@@ -303,7 +303,8 @@ function createDOMPurify() {
303
303
  var _document = document,
304
304
  implementation = _document.implementation,
305
305
  createNodeIterator = _document.createNodeIterator,
306
- createDocumentFragment = _document.createDocumentFragment;
306
+ createDocumentFragment = _document.createDocumentFragment,
307
+ getElementsByTagName = _document.getElementsByTagName;
307
308
  var importNode = originalDocument.importNode;
308
309
 
309
310
 
@@ -410,7 +411,8 @@ function createDOMPurify() {
410
411
  var USE_PROFILES = {};
411
412
 
412
413
  /* Tags to ignore content of when KEEP_CONTENT is true */
413
- var FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);
414
+ var FORBID_CONTENTS = null;
415
+ var DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);
414
416
 
415
417
  /* Tags that are safe for data: URIs */
416
418
  var DATA_URI_TAGS = null;
@@ -418,7 +420,7 @@ function createDOMPurify() {
418
420
 
419
421
  /* Attributes safe for values like "javascript:" */
420
422
  var URI_SAFE_ATTRIBUTES = null;
421
- var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'summary', 'title', 'value', 'style', 'xmlns']);
423
+ var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
422
424
 
423
425
  var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
424
426
  var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
@@ -427,6 +429,12 @@ function createDOMPurify() {
427
429
  var NAMESPACE = HTML_NAMESPACE;
428
430
  var IS_EMPTY_INPUT = false;
429
431
 
432
+ /* Parsing of strict XHTML documents */
433
+ var PARSER_MEDIA_TYPE = void 0;
434
+ var SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
435
+ var DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
436
+ var transformCaseFunc = void 0;
437
+
430
438
  /* Keep a reference to config to pass to hooks */
431
439
  var CONFIG = null;
432
440
 
@@ -459,6 +467,7 @@ function createDOMPurify() {
459
467
  ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR;
460
468
  URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR) : DEFAULT_URI_SAFE_ATTRIBUTES;
461
469
  DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS) : DEFAULT_DATA_URI_TAGS;
470
+ FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS) : DEFAULT_FORBID_CONTENTS;
462
471
  FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS) : {};
463
472
  FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR) : {};
464
473
  USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
@@ -477,6 +486,16 @@ function createDOMPurify() {
477
486
  IN_PLACE = cfg.IN_PLACE || false; // Default false
478
487
  IS_ALLOWED_URI$$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$$1;
479
488
  NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
489
+
490
+ PARSER_MEDIA_TYPE =
491
+ // eslint-disable-next-line unicorn/prefer-includes
492
+ SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE;
493
+
494
+ // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
495
+ transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? function (x) {
496
+ return x;
497
+ } : stringToLowerCase;
498
+
480
499
  if (SAFE_FOR_TEMPLATES) {
481
500
  ALLOW_DATA_ATTR = false;
482
501
  }
@@ -534,6 +553,14 @@ function createDOMPurify() {
534
553
  addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR);
535
554
  }
536
555
 
556
+ if (cfg.FORBID_CONTENTS) {
557
+ if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
558
+ FORBID_CONTENTS = clone(FORBID_CONTENTS);
559
+ }
560
+
561
+ addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS);
562
+ }
563
+
537
564
  /* Add #text in case KEEP_CONTENT is set to true */
538
565
  if (KEEP_CONTENT) {
539
566
  ALLOWED_TAGS['#text'] = true;
@@ -737,6 +764,11 @@ function createDOMPurify() {
737
764
  leadingWhitespace = matches && matches[0];
738
765
  }
739
766
 
767
+ if (PARSER_MEDIA_TYPE === 'application/xhtml+xml') {
768
+ // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
769
+ dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
770
+ }
771
+
740
772
  var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
741
773
  /*
742
774
  * Use the DOMParser API by default, fallback later if needs be
@@ -744,7 +776,7 @@ function createDOMPurify() {
744
776
  */
745
777
  if (NAMESPACE === HTML_NAMESPACE) {
746
778
  try {
747
- doc = new DOMParser().parseFromString(dirtyPayload, 'text/html');
779
+ doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
748
780
  } catch (_) {}
749
781
  }
750
782
 
@@ -765,6 +797,10 @@ function createDOMPurify() {
765
797
  }
766
798
 
767
799
  /* Work on whole document or just its body */
800
+ if (NAMESPACE === HTML_NAMESPACE) {
801
+ return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
802
+ }
803
+
768
804
  return WHOLE_DOCUMENT ? doc.documentElement : body;
769
805
  };
770
806
 
@@ -853,7 +889,7 @@ function createDOMPurify() {
853
889
  }
854
890
 
855
891
  /* Now let's check the element's type and name */
856
- var tagName = stringToLowerCase(currentNode.nodeName);
892
+ var tagName = transformCaseFunc(currentNode.nodeName);
857
893
 
858
894
  /* Execute a hook if present */
859
895
  _executeHook('uponSanitizeElement', currentNode, {
@@ -867,6 +903,12 @@ function createDOMPurify() {
867
903
  return true;
868
904
  }
869
905
 
906
+ /* Mitigate a problem with templates inside select */
907
+ if (tagName === 'select' && regExpTest(/<template/i, currentNode.innerHTML)) {
908
+ _forceRemove(currentNode);
909
+ return true;
910
+ }
911
+
870
912
  /* Remove element if anything forbids its presence */
871
913
  if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
872
914
  /* Keep content except for bad-listed elements */
@@ -935,7 +977,7 @@ function createDOMPurify() {
935
977
  (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
936
978
  XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
937
979
  We don't need to check the value; it's always URI safe. */
938
- if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$$1, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$$1, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
980
+ if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR$$1, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$$1, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
939
981
  return false;
940
982
 
941
983
  /* Check value is safe. First, is attr inert? If so, is safe */
@@ -988,7 +1030,7 @@ function createDOMPurify() {
988
1030
  namespaceURI = _attr.namespaceURI;
989
1031
 
990
1032
  value = stringTrim(attr.value);
991
- lcName = stringToLowerCase(name);
1033
+ lcName = transformCaseFunc(name);
992
1034
 
993
1035
  /* Execute a hook if present */
994
1036
  hookEvent.attrName = lcName;
@@ -1023,7 +1065,7 @@ function createDOMPurify() {
1023
1065
  }
1024
1066
 
1025
1067
  /* Is `value` valid for this attribute? */
1026
- var lcTag = currentNode.nodeName.toLowerCase();
1068
+ var lcTag = transformCaseFunc(currentNode.nodeName);
1027
1069
  if (!_isValidAttribute(lcTag, lcName, value)) {
1028
1070
  continue;
1029
1071
  }
@@ -1286,8 +1328,8 @@ function createDOMPurify() {
1286
1328
  _parseConfig({});
1287
1329
  }
1288
1330
 
1289
- var lcTag = stringToLowerCase(tag);
1290
- var lcName = stringToLowerCase(attr);
1331
+ var lcTag = transformCaseFunc(tag);
1332
+ var lcName = transformCaseFunc(attr);
1291
1333
  return _isValidAttribute(lcTag, lcName, value);
1292
1334
  };
1293
1335