dompurify 2.2.5 → 2.2.9

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,7 +6,7 @@
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.5.
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.
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
 
@@ -160,6 +160,8 @@ var clean = DOMPurify.sanitize(dirty, {ALLOWED_TAGS: ['b']});
160
160
  var clean = DOMPurify.sanitize(dirty, {ALLOWED_TAGS: ['b', 'q'], ALLOWED_ATTR: ['style']});
161
161
 
162
162
  // allow all safe HTML elements but neither SVG nor MathML
163
+ // note that the USE_PROFILES setting will override the ALLOWED_TAGS setting
164
+ // so don't use them together
163
165
  var clean = DOMPurify.sanitize(dirty, {USE_PROFILES: {html: true}});
164
166
 
165
167
  // allow all safe SVG elements and SVG Filters, no HTML or MathML
@@ -168,6 +170,9 @@ var clean = DOMPurify.sanitize(dirty, {USE_PROFILES: {svg: true, svgFilters: tru
168
170
  // allow all safe MathML elements and SVG, but no SVG Filters
169
171
  var clean = DOMPurify.sanitize(dirty, {USE_PROFILES: {mathMl: true, svg: true}});
170
172
 
173
+ // change the default namespace from HTML to something different
174
+ var clean = DOMPurify.sanitize(dirty, {NAMESPACE: 'http://www.w3.org/2000/svg'});
175
+
171
176
  // leave all safe HTML as it is and add <style> elements to block-list
172
177
  var clean = DOMPurify.sanitize(dirty, {FORBID_TAGS: ['style']});
173
178
 
@@ -332,7 +337,7 @@ Feature releases will not be announced to this list.
332
337
 
333
338
  Many people helped and help DOMPurify become what it is and need to be acknowledged here!
334
339
 
335
- [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), [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) and especially [@securitymb ❤️](https://twitter.com/securitymb) & [@masatokinugawa ❤️](https://twitter.com/masatokinugawa)
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)
336
341
 
337
342
  ## Testing powered by
338
343
  <a target="_blank" href="https://www.browserstack.com/"><img width="200" src="https://www.browserstack.com/images/layout/browserstack-logo-600x315.png"></a><br>
@@ -139,7 +139,12 @@ function lookupGetter(object, prop) {
139
139
  object = getPrototypeOf(object);
140
140
  }
141
141
 
142
- return null;
142
+ function fallbackValue(element) {
143
+ console.warn('fallback value for', element);
144
+ return null;
145
+ }
146
+
147
+ return fallbackValue;
143
148
  }
144
149
 
145
150
  var html = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'shadow', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']);
@@ -163,7 +168,7 @@ var mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv
163
168
 
164
169
  var text = freeze(['#text']);
165
170
 
166
- var html$1 = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns']);
171
+ var html$1 = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns', 'slot']);
167
172
 
168
173
  var svg$1 = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'targetx', 'targety', 'transform', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
169
174
 
@@ -240,7 +245,7 @@ function createDOMPurify() {
240
245
  * Version label, exposed for easier checks
241
246
  * if DOMPurify is up to date or not
242
247
  */
243
- DOMPurify.version = '2.2.5';
248
+ DOMPurify.version = '2.2.9';
244
249
 
245
250
  /**
246
251
  * Array of elements that DOMPurify removed during sanitation.
@@ -298,7 +303,6 @@ function createDOMPurify() {
298
303
  var _document = document,
299
304
  implementation = _document.implementation,
300
305
  createNodeIterator = _document.createNodeIterator,
301
- getElementsByTagName = _document.getElementsByTagName,
302
306
  createDocumentFragment = _document.createDocumentFragment;
303
307
  var importNode = originalDocument.importNode;
304
308
 
@@ -313,7 +317,7 @@ function createDOMPurify() {
313
317
  /**
314
318
  * Expose whether this browser supports running the full DOMPurify.
315
319
  */
316
- DOMPurify.isSupported = implementation && typeof implementation.createHTMLDocument !== 'undefined' && documentMode !== 9;
320
+ DOMPurify.isSupported = typeof getParentNode === 'function' && implementation && typeof implementation.createHTMLDocument !== 'undefined' && documentMode !== 9;
317
321
 
318
322
  var MUSTACHE_EXPR$$1 = MUSTACHE_EXPR,
319
323
  ERB_EXPR$$1 = ERB_EXPR,
@@ -416,6 +420,13 @@ function createDOMPurify() {
416
420
  var URI_SAFE_ATTRIBUTES = null;
417
421
  var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'summary', 'title', 'value', 'style', 'xmlns']);
418
422
 
423
+ var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
424
+ var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
425
+ var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
426
+ /* Document namespace */
427
+ var NAMESPACE = HTML_NAMESPACE;
428
+ var IS_EMPTY_INPUT = false;
429
+
419
430
  /* Keep a reference to config to pass to hooks */
420
431
  var CONFIG = null;
421
432
 
@@ -465,6 +476,7 @@ function createDOMPurify() {
465
476
  KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
466
477
  IN_PLACE = cfg.IN_PLACE || false; // Default false
467
478
  IS_ALLOWED_URI$$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$$1;
479
+ NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
468
480
  if (SAFE_FOR_TEMPLATES) {
469
481
  ALLOW_DATA_ATTR = false;
470
482
  }
@@ -561,10 +573,6 @@ function createDOMPurify() {
561
573
  var ALL_MATHML_TAGS = addToSet({}, mathMl);
562
574
  addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
563
575
 
564
- var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
565
- var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
566
- var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
567
-
568
576
  /**
569
577
  *
570
578
  *
@@ -664,6 +672,7 @@ function createDOMPurify() {
664
672
  var _forceRemove = function _forceRemove(node) {
665
673
  arrayPush(DOMPurify.removed, { element: node });
666
674
  try {
675
+ // eslint-disable-next-line unicorn/prefer-dom-node-remove
667
676
  node.parentNode.removeChild(node);
668
677
  } catch (_) {
669
678
  try {
@@ -694,6 +703,19 @@ function createDOMPurify() {
694
703
  }
695
704
 
696
705
  node.removeAttribute(name);
706
+
707
+ // We void attribute values for unremovable "is"" attributes
708
+ if (name === 'is' && !ALLOWED_ATTR[name]) {
709
+ if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
710
+ try {
711
+ _forceRemove(node);
712
+ } catch (_) {}
713
+ } else {
714
+ try {
715
+ node.setAttribute(name, '');
716
+ } catch (_) {}
717
+ }
718
+ }
697
719
  };
698
720
 
699
721
  /**
@@ -716,27 +738,34 @@ function createDOMPurify() {
716
738
  }
717
739
 
718
740
  var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
719
- /* Use the DOMParser API by default, fallback later if needs be */
720
- try {
721
- doc = new DOMParser().parseFromString(dirtyPayload, 'text/html');
722
- } catch (_) {}
741
+ /*
742
+ * Use the DOMParser API by default, fallback later if needs be
743
+ * DOMParser not work for svg when has multiple root element.
744
+ */
745
+ if (NAMESPACE === HTML_NAMESPACE) {
746
+ try {
747
+ doc = new DOMParser().parseFromString(dirtyPayload, 'text/html');
748
+ } catch (_) {}
749
+ }
723
750
 
724
751
  /* Use createHTMLDocument in case DOMParser is not available */
725
752
  if (!doc || !doc.documentElement) {
726
- doc = implementation.createHTMLDocument('');
727
- var _doc = doc,
728
- body = _doc.body;
729
-
730
- body.parentNode.removeChild(body.parentNode.firstElementChild);
731
- body.outerHTML = dirtyPayload;
753
+ doc = implementation.createDocument(NAMESPACE, 'template', null);
754
+ try {
755
+ doc.documentElement.innerHTML = IS_EMPTY_INPUT ? '' : dirtyPayload;
756
+ } catch (_) {
757
+ // Syntax error if dirtyPayload is invalid xml
758
+ }
732
759
  }
733
760
 
761
+ var body = doc.body || doc.documentElement;
762
+
734
763
  if (dirty && leadingWhitespace) {
735
- doc.body.insertBefore(document.createTextNode(leadingWhitespace), doc.body.childNodes[0] || null);
764
+ body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
736
765
  }
737
766
 
738
767
  /* Work on whole document or just its body */
739
- return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
768
+ return WHOLE_DOCUMENT ? doc.documentElement : body;
740
769
  };
741
770
 
742
771
  /**
@@ -746,9 +775,7 @@ function createDOMPurify() {
746
775
  * @return {Iterator} iterator instance
747
776
  */
748
777
  var _createIterator = function _createIterator(root) {
749
- return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, function () {
750
- return NodeFilter.FILTER_ACCEPT;
751
- }, false);
778
+ return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);
752
779
  };
753
780
 
754
781
  /**
@@ -844,11 +871,15 @@ function createDOMPurify() {
844
871
  if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
845
872
  /* Keep content except for bad-listed elements */
846
873
  if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
847
- var parentNode = getParentNode(currentNode);
848
- var childNodes = getChildNodes(currentNode);
849
- var childCount = childNodes.length;
850
- for (var i = childCount - 1; i >= 0; --i) {
851
- parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
874
+ var parentNode = getParentNode(currentNode) || currentNode.parentNode;
875
+ var childNodes = getChildNodes(currentNode) || currentNode.childNodes;
876
+
877
+ if (childNodes && parentNode) {
878
+ var childCount = childNodes.length;
879
+
880
+ for (var i = childCount - 1; i >= 0; --i) {
881
+ parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
882
+ }
852
883
  }
853
884
  }
854
885
 
@@ -1065,7 +1096,8 @@ function createDOMPurify() {
1065
1096
  /* Make sure we have a string to sanitize.
1066
1097
  DO NOT return early, as this will return the wrong type if
1067
1098
  the user has requested a DOM object rather than a string */
1068
- if (!dirty) {
1099
+ IS_EMPTY_INPUT = !dirty;
1100
+ if (IS_EMPTY_INPUT) {
1069
1101
  dirty = '<!-->';
1070
1102
  }
1071
1103
 
@@ -1121,7 +1153,7 @@ function createDOMPurify() {
1121
1153
  } else if (importedNode.nodeName === 'HTML') {
1122
1154
  body = importedNode;
1123
1155
  } else {
1124
- // eslint-disable-next-line unicorn/prefer-node-append
1156
+ // eslint-disable-next-line unicorn/prefer-dom-node-append
1125
1157
  body.appendChild(importedNode);
1126
1158
  }
1127
1159
  } else {
@@ -1185,7 +1217,7 @@ function createDOMPurify() {
1185
1217
  returnNode = createDocumentFragment.call(body.ownerDocument);
1186
1218
 
1187
1219
  while (body.firstChild) {
1188
- // eslint-disable-next-line unicorn/prefer-node-append
1220
+ // eslint-disable-next-line unicorn/prefer-dom-node-append
1189
1221
  returnNode.appendChild(body.firstChild);
1190
1222
  }
1191
1223
  } else {