dompurify 2.0.15 → 2.1.1

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
@@ -10,8 +10,7 @@
10
10
 
11
11
  var hasOwnProperty = Object.hasOwnProperty,
12
12
  setPrototypeOf = Object.setPrototypeOf,
13
- isFrozen = Object.isFrozen,
14
- objectKeys = Object.keys;
13
+ isFrozen = Object.isFrozen;
15
14
  var freeze = Object.freeze,
16
15
  seal = Object.seal,
17
16
  create = Object.create; // eslint-disable-line import/no-mutable-exports
@@ -45,11 +44,8 @@
45
44
  }
46
45
 
47
46
  var arrayForEach = unapply(Array.prototype.forEach);
48
- var arrayIndexOf = unapply(Array.prototype.indexOf);
49
- var arrayJoin = unapply(Array.prototype.join);
50
47
  var arrayPop = unapply(Array.prototype.pop);
51
48
  var arrayPush = unapply(Array.prototype.push);
52
- var arraySlice = unapply(Array.prototype.slice);
53
49
 
54
50
  var stringToLowerCase = unapply(String.prototype.toLowerCase);
55
51
  var stringMatch = unapply(String.prototype.match);
@@ -58,7 +54,6 @@
58
54
  var stringTrim = unapply(String.prototype.trim);
59
55
 
60
56
  var regExpTest = unapply(RegExp.prototype.test);
61
- var regExpCreate = unconstruct(RegExp);
62
57
 
63
58
  var typeErrorCreate = unconstruct(TypeError);
64
59
 
@@ -214,7 +209,7 @@
214
209
  * Version label, exposed for easier checks
215
210
  * if DOMPurify is up to date or not
216
211
  */
217
- DOMPurify.version = '2.0.15';
212
+ DOMPurify.version = '2.1.1';
218
213
 
219
214
  /**
220
215
  * Array of elements that DOMPurify removed during sanitation.
@@ -231,7 +226,6 @@
231
226
  }
232
227
 
233
228
  var originalDocument = window.document;
234
- var removeTitle = false;
235
229
 
236
230
  var document = window.document;
237
231
  var DocumentFragment = window.DocumentFragment,
@@ -270,7 +264,10 @@
270
264
  var importNode = originalDocument.importNode;
271
265
 
272
266
 
273
- var documentMode = clone(document).documentMode ? document.documentMode : {};
267
+ var documentMode = {};
268
+ try {
269
+ documentMode = clone(document).documentMode ? document.documentMode : {};
270
+ } catch (_) {}
274
271
 
275
272
  var hooks = {};
276
273
 
@@ -316,9 +313,6 @@
316
313
  /* Decide if unknown protocols are okay */
317
314
  var ALLOW_UNKNOWN_PROTOCOLS = false;
318
315
 
319
- /* Output should be safe for jQuery's $() factory? */
320
- var SAFE_FOR_JQUERY = false;
321
-
322
316
  /* Output should be safe for common template engines.
323
317
  * This means, DOMPurify removes data attributes, mustaches and ERB
324
318
  */
@@ -416,7 +410,6 @@
416
410
  ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
417
411
  ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
418
412
  ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
419
- SAFE_FOR_JQUERY = cfg.SAFE_FOR_JQUERY || false; // Default false
420
413
  SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
421
414
  WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
422
415
  RETURN_DOM = cfg.RETURN_DOM || false; // Default false
@@ -571,11 +564,6 @@
571
564
  doc = new DOMParser().parseFromString(dirtyPayload, 'text/html');
572
565
  } catch (_) {}
573
566
 
574
- /* Remove title to fix a mXSS bug in older MS Edge */
575
- if (removeTitle) {
576
- addToSet(FORBID_TAGS, ['title']);
577
- }
578
-
579
567
  /* Use createHTMLDocument in case DOMParser is not available */
580
568
  if (!doc || !doc.documentElement) {
581
569
  doc = implementation.createHTMLDocument('');
@@ -594,18 +582,6 @@
594
582
  return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
595
583
  };
596
584
 
597
- /* Here we test for a broken feature in Edge that might cause mXSS */
598
- if (DOMPurify.isSupported) {
599
- (function () {
600
- try {
601
- var doc = _initDocument('<x/><title>&lt;/title&gt;&lt;img&gt;');
602
- if (regExpTest(/<\/title/, doc.querySelector('title').innerHTML)) {
603
- removeTitle = true;
604
- }
605
- } catch (_) {}
606
- })();
607
- }
608
-
609
585
  /**
610
586
  * _createIterator
611
587
  *
@@ -674,7 +650,6 @@
674
650
  * @param {Node} currentNode to check for permission to exist
675
651
  * @return {Boolean} true if node was killed, false if left alive
676
652
  */
677
- // eslint-disable-next-line complexity
678
653
  var _sanitizeElements = function _sanitizeElements(currentNode) {
679
654
  var content = void 0;
680
655
 
@@ -708,6 +683,12 @@
708
683
  return true;
709
684
  }
710
685
 
686
+ /* Detect mXSS attempts abusing namespace confusion */
687
+ if (!_isNode(currentNode.firstElementChild) && (!_isNode(currentNode.content) || !_isNode(currentNode.content.firstElementChild)) && regExpTest(/<[!/\w]/g, currentNode.innerHTML) && regExpTest(/<[!/\w]/g, currentNode.textContent)) {
688
+ _forceRemove(currentNode);
689
+ return true;
690
+ }
691
+
711
692
  /* Remove element if anything forbids its presence */
712
693
  if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
713
694
  /* Keep content except for bad-listed elements */
@@ -723,26 +704,11 @@
723
704
  }
724
705
 
725
706
  /* Remove in case a noscript/noembed XSS is suspected */
726
- if (tagName === 'noscript' && regExpTest(/<\/noscript/i, currentNode.innerHTML)) {
727
- _forceRemove(currentNode);
728
- return true;
729
- }
730
-
731
- if (tagName === 'noembed' && regExpTest(/<\/noembed/i, currentNode.innerHTML)) {
707
+ if ((tagName === 'noscript' || tagName === 'noembed') && regExpTest(/<\/no(script|embed)/i, currentNode.innerHTML)) {
732
708
  _forceRemove(currentNode);
733
709
  return true;
734
710
  }
735
711
 
736
- /* Convert markup to cover jQuery behavior */
737
- if (SAFE_FOR_JQUERY && !_isNode(currentNode.firstElementChild) && (!_isNode(currentNode.content) || !_isNode(currentNode.content.firstElementChild)) && regExpTest(/</g, currentNode.textContent)) {
738
- arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });
739
- if (currentNode.innerHTML) {
740
- currentNode.innerHTML = stringReplace(currentNode.innerHTML, /</g, '&lt;');
741
- } else {
742
- currentNode.innerHTML = stringReplace(currentNode.textContent, /</g, '&lt;');
743
- }
744
- }
745
-
746
712
  /* Sanitize element content to be template-safe */
747
713
  if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
748
714
  /* Get the element's text content */
@@ -801,12 +767,10 @@
801
767
  *
802
768
  * @param {Node} currentNode to sanitize
803
769
  */
804
- // eslint-disable-next-line complexity
805
770
  var _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
806
771
  var attr = void 0;
807
772
  var value = void 0;
808
773
  var lcName = void 0;
809
- var idAttr = void 0;
810
774
  var l = void 0;
811
775
  /* Execute a hook if present */
812
776
  _executeHook('beforeSanitizeAttributes', currentNode, null);
@@ -850,32 +814,7 @@
850
814
  }
851
815
 
852
816
  /* Remove attribute */
853
- // Safari (iOS + Mac), last tested v8.0.5, crashes if you try to
854
- // remove a "name" attribute from an <img> tag that has an "id"
855
- // attribute at the time.
856
- if (lcName === 'name' && currentNode.nodeName === 'IMG' && attributes.id) {
857
- idAttr = attributes.id;
858
- attributes = arraySlice(attributes, []);
859
- _removeAttribute('id', currentNode);
860
- _removeAttribute(name, currentNode);
861
- if (arrayIndexOf(attributes, idAttr) > l) {
862
- currentNode.setAttribute('id', idAttr.value);
863
- }
864
- } else if (
865
- // This works around a bug in Safari, where input[type=file]
866
- // cannot be dynamically set after type has been removed
867
- currentNode.nodeName === 'INPUT' && lcName === 'type' && value === 'file' && hookEvent.keepAttr && (ALLOWED_ATTR[lcName] || !FORBID_ATTR[lcName])) {
868
- continue;
869
- } else {
870
- // This avoids a crash in Safari v9.0 with double-ids.
871
- // The trick is to first set the id to be empty and then to
872
- // remove the attribute
873
- if (name === 'id') {
874
- currentNode.setAttribute(name, '');
875
- }
876
-
877
- _removeAttribute(name, currentNode);
878
- }
817
+ _removeAttribute(name, currentNode);
879
818
 
880
819
  /* Did the hooks approve of the attribute? */
881
820
  if (!hookEvent.keepAttr) {
@@ -883,13 +822,7 @@
883
822
  }
884
823
 
885
824
  /* Work around a security issue in jQuery 3.0 */
886
- if (SAFE_FOR_JQUERY && regExpTest(/\/>/i, value)) {
887
- _removeAttribute(name, currentNode);
888
- continue;
889
- }
890
-
891
- /* Take care of an mXSS pattern using namespace switches */
892
- if (regExpTest(/svg|math/i, currentNode.namespaceURI) && regExpTest(regExpCreate('</(' + arrayJoin(objectKeys(FORBID_CONTENTS), '|') + ')', 'i'), value)) {
825
+ if (regExpTest(/\/>/i, value)) {
893
826
  _removeAttribute(name, currentNode);
894
827
  continue;
895
828
  }
@@ -1022,7 +955,7 @@
1022
955
  if (IN_PLACE) ; else if (dirty instanceof Node) {
1023
956
  /* If dirty is a DOM element, append to an empty document to avoid
1024
957
  elements being stripped by the parser */
1025
- body = _initDocument('<!-->');
958
+ body = _initDocument('<!---->');
1026
959
  importedNode = body.ownerDocument.importNode(dirty, true);
1027
960
  if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
1028
961
  /* Node is already a body, use as is */