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/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.3.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.3.11.
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 [19 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, v16.13.0, v17.0.0, running DOMPurify on [jsdom](https://github.com/jsdom/jsdom). Older Node.js versions are known to work as well.
13
+ Our automated tests cover [19 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.x, v16.x, v17.x and v18.x, running DOMPurify on [jsdom](https://github.com/jsdom/jsdom). Older Node versions are known to work as well, but hey... no guarantees.
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
 
@@ -40,6 +40,14 @@ Afterwards you can sanitize strings by executing the following code:
40
40
  let clean = DOMPurify.sanitize(dirty);
41
41
  ```
42
42
 
43
+ Or maybe this, if you love working with Angular or alike:
44
+
45
+ ```js
46
+ import * as DOMPurify from 'dompurify';
47
+
48
+ let clean = DOMPurify.sanitize('<b>hello there</b>');
49
+ ```
50
+
43
51
  The resulting HTML can be written into a DOM element using `innerHTML` or the DOM using `document.write()`. That is fully up to you.
44
52
  Note that by default, we permit HTML, SVG **and** MathML. If you only need HTML, which might be a very common use-case, you can easily set that up as well:
45
53
 
@@ -55,21 +63,22 @@ Well, please note, if you _first_ sanitize HTML and then modify it _afterwards_,
55
63
 
56
64
  After sanitizing your markup, you can also have a look at the property `DOMPurify.removed` and find out, what elements and attributes were thrown out. Please **do not use** this property for making any security critical decisions. This is just a little helper for curious minds.
57
65
 
58
- If you're using an [AMD](https://github.com/amdjs/amdjs-api/blob/master/AMD.md) module loader like [Require.js](http://requirejs.org/), you can load this script asynchronously as well:
66
+ ### Running DOMPurify on the server
59
67
 
60
- ```js
61
- import DOMPurify from 'dompurify';
68
+ DOMPurify technically also works server-side with Node.js. Our support strives to follow the [Node.js release cycle](https://nodejs.org/en/about/releases/).
62
69
 
63
- var clean = DOMPurify.sanitize(dirty);
64
- ```
70
+ Running DOMPurify on the server requires a DOM to be present, which is probably no surprise. Usually, [jsdom](https://github.com/jsdom/jsdom) is the tool of choice and we **strongly recommend** to use the latest version of _jsdom_.
71
+
72
+ Why? Because older versions of _jsdom_ are known to be buggy in ways that result in XSS _even if_ DOMPurify does everything 100% correctly. There are **known attack vectors** in, e.g. _jsdom v19.0.0_ that are fixed in _jsdom v20.0.0_ - and we really recommend to keep _jsdom_ up to date because of that.
65
73
 
66
- DOMPurify also works server-side with Node.js as well as client-side via [Browserify](http://browserify.org/) or similar translators. At least Node.js 4.x or newer is required. Our support strives to follow the [Node.js release cycle](https://nodejs.org/en/about/releases/). DOMPurify intends to support any version being flagged as active. At the same time we phase out support for any version flagged as maintenance. DOMPurify might not break with all versions in maintenance immediately but stops to run tests against these older versions.
74
+ Other than that, you are fine to use DOMPurify on the server. Probably. This really depends on _jsdom_ or whatever DOM you utilize server-side. If you can live with that, this is how you get it to work:
67
75
 
68
76
  ```bash
69
77
  npm install dompurify
78
+ npm install jsdom
70
79
  ```
71
80
 
72
- For JSDOM v10 or newer
81
+ For _jsdom_ (please use an up-to-date version), this should do the trick:
73
82
 
74
83
  ```js
75
84
  const createDOMPurify = require('dompurify');
@@ -77,20 +86,30 @@ const { JSDOM } = require('jsdom');
77
86
 
78
87
  const window = new JSDOM('').window;
79
88
  const DOMPurify = createDOMPurify(window);
80
-
81
- const clean = DOMPurify.sanitize(dirty);
89
+ const clean = DOMPurify.sanitize('<b>hello there</b>');
82
90
  ```
83
91
 
84
- For JSDOM versions older than v10
92
+ Or even this, if you prefer working with imports:
85
93
 
86
94
  ```js
87
- const createDOMPurify = require('dompurify');
88
- const jsdom = require('jsdom').jsdom;
95
+ import { JSDOM } from 'jsdom';
96
+ import DOMPurify from 'dompurify';
89
97
 
90
- const window = jsdom('').defaultView;
91
- const DOMPurify = createDOMPurify(window);
98
+ const window = new JSDOM('').window;
99
+ const purify = DOMPurify(window);
100
+ const clean = purify.sanitize('<b>hello there</b>');
101
+ ```
92
102
 
93
- const clean = DOMPurify.sanitize(dirty);
103
+ If you have problems making it work in your specific setup, consider looking at the amazing [isomorphic-dompurify](https://github.com/kkomelin/isomorphic-dompurify) project which solves lots of problems people might run into.
104
+
105
+ ```bash
106
+ npm install isomorphic-dompurify
107
+ ```
108
+
109
+ ```js
110
+ import DOMPurify from 'isomorphic-dompurify';
111
+
112
+ const clean = DOMPurify.sanitize('<s>hello</s>');
94
113
  ```
95
114
 
96
115
  ## Is there a demo?
@@ -279,12 +298,20 @@ var clean = DOMPurify.sanitize(dirty, {WHOLE_DOCUMENT: true});
279
298
  // disable DOM Clobbering protection on output (default is true, handle with care, minor XSS risks here)
280
299
  var clean = DOMPurify.sanitize(dirty, {SANITIZE_DOM: false});
281
300
 
301
+ // enforce strict DOM Clobbering protection via namespace isolation (default is false)
302
+ // when enabled, isolates the namespace of named properties (i.e., `id` and `name` attributes)
303
+ // from JS variables by prefixing them with the string `user-content-`
304
+ var clean = DOMPurify.sanitize(dirty, {SANITIZE_NAMED_PROPS: true});
305
+
282
306
  // keep an element's content when the element is removed (default is true)
283
307
  var clean = DOMPurify.sanitize(dirty, {KEEP_CONTENT: false});
284
308
 
285
309
  // glue elements like style, script or others to document.body and prevent unintuitive browser behavior in several edge-cases (default is false)
286
310
  var clean = DOMPurify.sanitize(dirty, {FORCE_BODY: true});
287
311
 
312
+ // remove all <a> elements under <p> elements that are removed
313
+ var clean = DOMPurify.sanitize(dirty, {FORBID_CONTENTS: ['a'], FORBID_TAGS: ['p']});
314
+
288
315
  // change the parser type so sanitized data is treated as XML and not as HTML, which is the default
289
316
  var clean = DOMPurify.sanitize(dirty, {PARSER_MEDIA_TYPE: 'application/xhtml+xml'});
290
317
 
@@ -378,7 +405,7 @@ Feature releases will not be announced to this list.
378
405
 
379
406
  Many people helped and help DOMPurify become what it is and need to be acknowledged here!
380
407
 
381
- [JGraph 💸](https://github.com/jgraph), [Sentry 💸](https://github.com/getsentry), [jarrodldavis 💸](https://github.com/jarrodldavis), [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), [is2ei](https://github.com/is2ei), [franktopel](https://github.com/franktopel), [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)
408
+ [JGraph 💸](https://github.com/jgraph), [GitHub 💸](https://github.com/github), [CynegeticIO 💸](https://github.com/CynegeticIO), [Sentry 💸](https://github.com/getsentry), [jarrodldavis 💸](https://github.com/jarrodldavis), [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), [is2ei](https://github.com/is2ei), [SoheilKhodayari](https://github.com/SoheilKhodayari), [franktopel](https://github.com/franktopel), [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)
382
409
 
383
410
  ## Testing powered by
384
411
 
@@ -0,0 +1,144 @@
1
+ export = purify;
2
+ declare function purify(root: any): {
3
+ (root: any): any;
4
+ /**
5
+ * Version label, exposed for easier checks
6
+ * if DOMPurify is up to date or not
7
+ */
8
+ version: string;
9
+ /**
10
+ * Array of elements that DOMPurify removed during sanitation.
11
+ * Empty if nothing was removed.
12
+ */
13
+ removed: any[];
14
+ isSupported: boolean;
15
+ /**
16
+ * Sanitize
17
+ * Public method providing core sanitation functionality
18
+ *
19
+ * @param {String|Node} dirty string or DOM node
20
+ * @param {Object} configuration object
21
+ */
22
+ sanitize(dirty: string | Node, cfg: any): any;
23
+ /**
24
+ * Public method to set the configuration once
25
+ * setConfig
26
+ *
27
+ * @param {Object} cfg configuration object
28
+ */
29
+ setConfig(cfg: any): void;
30
+ /**
31
+ * Public method to remove the configuration
32
+ * clearConfig
33
+ *
34
+ */
35
+ clearConfig(): void;
36
+ /**
37
+ * Public method to check if an attribute value is valid.
38
+ * Uses last set config, if any. Otherwise, uses config defaults.
39
+ * isValidAttribute
40
+ *
41
+ * @param {string} tag Tag name of containing element.
42
+ * @param {string} attr Attribute name.
43
+ * @param {string} value Attribute value.
44
+ * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.
45
+ */
46
+ isValidAttribute(tag: string, attr: string, value: string): boolean;
47
+ /**
48
+ * AddHook
49
+ * Public method to add DOMPurify hooks
50
+ *
51
+ * @param {String} entryPoint entry point for the hook to add
52
+ * @param {Function} hookFunction function to execute
53
+ */
54
+ addHook(entryPoint: string, hookFunction: Function): void;
55
+ /**
56
+ * RemoveHook
57
+ * Public method to remove a DOMPurify hook at a given entryPoint
58
+ * (pops it from the stack of hooks if more are present)
59
+ *
60
+ * @param {String} entryPoint entry point for the hook to remove
61
+ * @return {Function} removed(popped) hook
62
+ */
63
+ removeHook(entryPoint: string): Function;
64
+ /**
65
+ * RemoveHooks
66
+ * Public method to remove all DOMPurify hooks at a given entryPoint
67
+ *
68
+ * @param {String} entryPoint entry point for the hooks to remove
69
+ */
70
+ removeHooks(entryPoint: string): void;
71
+ /**
72
+ * RemoveAllHooks
73
+ * Public method to remove all DOMPurify hooks
74
+ *
75
+ */
76
+ removeAllHooks(): void;
77
+ };
78
+ declare namespace purify {
79
+ const version: string;
80
+ const removed: any[];
81
+ const isSupported: boolean;
82
+ /**
83
+ * Sanitize
84
+ * Public method providing core sanitation functionality
85
+ *
86
+ * @param {String|Node} dirty string or DOM node
87
+ * @param {Object} configuration object
88
+ */
89
+ function sanitize(dirty: string | Node, cfg: any): any;
90
+ /**
91
+ * Public method to set the configuration once
92
+ * setConfig
93
+ *
94
+ * @param {Object} cfg configuration object
95
+ */
96
+ function setConfig(cfg: any): void;
97
+ /**
98
+ * Public method to remove the configuration
99
+ * clearConfig
100
+ *
101
+ */
102
+ function clearConfig(): void;
103
+ /**
104
+ * Public method to check if an attribute value is valid.
105
+ * Uses last set config, if any. Otherwise, uses config defaults.
106
+ * isValidAttribute
107
+ *
108
+ * @param {string} tag Tag name of containing element.
109
+ * @param {string} attr Attribute name.
110
+ * @param {string} value Attribute value.
111
+ * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.
112
+ */
113
+ function isValidAttribute(tag: string, attr: string, value: string): boolean;
114
+ /**
115
+ * AddHook
116
+ * Public method to add DOMPurify hooks
117
+ *
118
+ * @param {String} entryPoint entry point for the hook to add
119
+ * @param {Function} hookFunction function to execute
120
+ */
121
+ function addHook(entryPoint: string, hookFunction: Function): void;
122
+ /**
123
+ * RemoveHook
124
+ * Public method to remove a DOMPurify hook at a given entryPoint
125
+ * (pops it from the stack of hooks if more are present)
126
+ *
127
+ * @param {String} entryPoint entry point for the hook to remove
128
+ * @return {Function} removed(popped) hook
129
+ */
130
+ function removeHook(entryPoint: string): Function;
131
+ /**
132
+ * RemoveHooks
133
+ * Public method to remove all DOMPurify hooks at a given entryPoint
134
+ *
135
+ * @param {String} entryPoint entry point for the hooks to remove
136
+ */
137
+ function removeHooks(entryPoint: string): void;
138
+ /**
139
+ * RemoveAllHooks
140
+ * Public method to remove all DOMPurify hooks
141
+ *
142
+ */
143
+ function removeAllHooks(): void;
144
+ }
@@ -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
  'use strict';
4
4
 
@@ -151,7 +151,9 @@ function unconstruct(func) {
151
151
  }
152
152
  /* Add properties to a lookup table */
153
153
 
154
- function addToSet(set, array) {
154
+ function addToSet(set, array, transformCaseFunc) {
155
+ transformCaseFunc = transformCaseFunc ? transformCaseFunc : stringToLowerCase;
156
+
155
157
  if (setPrototypeOf) {
156
158
  // Make 'in' and truthy checks like Boolean(set.constructor)
157
159
  // independent of any properties defined on Object.prototype.
@@ -165,7 +167,7 @@ function addToSet(set, array) {
165
167
  var element = array[l];
166
168
 
167
169
  if (typeof element === 'string') {
168
- var lcElement = stringToLowerCase(element);
170
+ var lcElement = transformCaseFunc(element);
169
171
 
170
172
  if (lcElement !== element) {
171
173
  // Config presets (e.g. tags.js, attrs.js) are immutable.
@@ -294,6 +296,9 @@ var _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes,
294
296
  return trustedTypes.createPolicy(policyName, {
295
297
  createHTML: function createHTML(html) {
296
298
  return html;
299
+ },
300
+ createScriptURL: function createScriptURL(scriptUrl) {
301
+ return scriptUrl;
297
302
  }
298
303
  });
299
304
  } catch (_) {
@@ -317,7 +322,7 @@ function createDOMPurify() {
317
322
  */
318
323
 
319
324
 
320
- DOMPurify.version = '2.3.8';
325
+ DOMPurify.version = '2.3.11';
321
326
  /**
322
327
  * Array of elements that DOMPurify removed during sanitation.
323
328
  * Empty if nothing was removed.
@@ -475,9 +480,27 @@ function createDOMPurify() {
475
480
  * case Trusted Types are not supported */
476
481
 
477
482
  var RETURN_TRUSTED_TYPE = false;
478
- /* Output should be free from DOM clobbering attacks? */
483
+ /* Output should be free from DOM clobbering attacks?
484
+ * This sanitizes markups named with colliding, clobberable built-in DOM APIs.
485
+ */
479
486
 
480
487
  var SANITIZE_DOM = true;
488
+ /* Achieve full DOM Clobbering protection by isolating the namespace of named
489
+ * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
490
+ *
491
+ * HTML/DOM spec rules that enable DOM Clobbering:
492
+ * - Named Access on Window (§7.3.3)
493
+ * - DOM Tree Accessors (§3.1.5)
494
+ * - Form Element Parent-Child Relations (§4.10.3)
495
+ * - Iframe srcdoc / Nested WindowProxies (§4.8.5)
496
+ * - HTMLCollection (§4.2.10.2)
497
+ *
498
+ * Namespace isolation is implemented by prefixing `id` and `name` attributes
499
+ * with a constant string, i.e., `user-content-`
500
+ */
501
+
502
+ var SANITIZE_NAMED_PROPS = false;
503
+ var SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
481
504
  /* Keep element content when removing element? */
482
505
 
483
506
  var KEEP_CONTENT = true;
@@ -547,15 +570,29 @@ function createDOMPurify() {
547
570
 
548
571
 
549
572
  cfg = clone(cfg);
573
+ PARSER_MEDIA_TYPE = // eslint-disable-next-line unicorn/prefer-includes
574
+ 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.
575
+
576
+ transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? function (x) {
577
+ return x;
578
+ } : stringToLowerCase;
550
579
  /* Set configuration parameters */
551
580
 
552
- ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS) : DEFAULT_ALLOWED_TAGS;
553
- ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR;
554
- URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR) : DEFAULT_URI_SAFE_ATTRIBUTES;
555
- DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS) : DEFAULT_DATA_URI_TAGS;
556
- FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS) : DEFAULT_FORBID_CONTENTS;
557
- FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS) : {};
558
- FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR) : {};
581
+ ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
582
+ ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
583
+ URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), // eslint-disable-line indent
584
+ cfg.ADD_URI_SAFE_ATTR, // eslint-disable-line indent
585
+ transformCaseFunc // eslint-disable-line indent
586
+ ) // eslint-disable-line indent
587
+ : DEFAULT_URI_SAFE_ATTRIBUTES;
588
+ DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), // eslint-disable-line indent
589
+ cfg.ADD_DATA_URI_TAGS, // eslint-disable-line indent
590
+ transformCaseFunc // eslint-disable-line indent
591
+ ) // eslint-disable-line indent
592
+ : DEFAULT_DATA_URI_TAGS;
593
+ FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
594
+ FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
595
+ FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
559
596
  USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
560
597
  ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
561
598
 
@@ -577,6 +614,8 @@ function createDOMPurify() {
577
614
 
578
615
  SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
579
616
 
617
+ SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
618
+
580
619
  KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
581
620
 
582
621
  IN_PLACE = cfg.IN_PLACE || false; // Default false
@@ -596,13 +635,6 @@ function createDOMPurify() {
596
635
  CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
597
636
  }
598
637
 
599
- PARSER_MEDIA_TYPE = // eslint-disable-next-line unicorn/prefer-includes
600
- 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.
601
-
602
- transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? function (x) {
603
- return x;
604
- } : stringToLowerCase;
605
-
606
638
  if (SAFE_FOR_TEMPLATES) {
607
639
  ALLOW_DATA_ATTR = false;
608
640
  }
@@ -648,7 +680,7 @@ function createDOMPurify() {
648
680
  ALLOWED_TAGS = clone(ALLOWED_TAGS);
649
681
  }
650
682
 
651
- addToSet(ALLOWED_TAGS, cfg.ADD_TAGS);
683
+ addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
652
684
  }
653
685
 
654
686
  if (cfg.ADD_ATTR) {
@@ -656,11 +688,11 @@ function createDOMPurify() {
656
688
  ALLOWED_ATTR = clone(ALLOWED_ATTR);
657
689
  }
658
690
 
659
- addToSet(ALLOWED_ATTR, cfg.ADD_ATTR);
691
+ addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
660
692
  }
661
693
 
662
694
  if (cfg.ADD_URI_SAFE_ATTR) {
663
- addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR);
695
+ addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
664
696
  }
665
697
 
666
698
  if (cfg.FORBID_CONTENTS) {
@@ -668,7 +700,7 @@ function createDOMPurify() {
668
700
  FORBID_CONTENTS = clone(FORBID_CONTENTS);
669
701
  }
670
702
 
671
- addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS);
703
+ addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
672
704
  }
673
705
  /* Add #text in case KEEP_CONTENT is set to true */
674
706
 
@@ -1240,6 +1272,34 @@ function createDOMPurify() {
1240
1272
  if (!_isValidAttribute(lcTag, lcName, value)) {
1241
1273
  continue;
1242
1274
  }
1275
+ /* Full DOM Clobbering protection via namespace isolation,
1276
+ * Prefix id and name attributes with `user-content-`
1277
+ */
1278
+
1279
+
1280
+ if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
1281
+ // Remove the attribute with this value
1282
+ _removeAttribute(name, currentNode); // Prefix the value and later re-create the attribute with the sanitized value
1283
+
1284
+
1285
+ value = SANITIZE_NAMED_PROPS_PREFIX + value;
1286
+ }
1287
+ /* Handle attributes that require Trusted Types */
1288
+
1289
+
1290
+ if (trustedTypesPolicy && _typeof(trustedTypes) === 'object' && typeof trustedTypes.getAttributeType === 'function') {
1291
+ if (namespaceURI) ; else {
1292
+ switch (trustedTypes.getAttributeType(lcTag, lcName)) {
1293
+ case 'TrustedHTML':
1294
+ value = trustedTypesPolicy.createHTML(value);
1295
+ break;
1296
+
1297
+ case 'TrustedScriptURL':
1298
+ value = trustedTypesPolicy.createScriptURL(value);
1299
+ break;
1300
+ }
1301
+ }
1302
+ }
1243
1303
  /* Handle invalid data-* attribute set by try-catching it */
1244
1304
 
1245
1305