dompurify 3.2.5 → 3.2.6

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
@@ -4,13 +4,13 @@
4
4
 
5
5
  DOMPurify is a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG.
6
6
 
7
- 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 **v3.2.5**.
7
+ 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 **v3.2.6**.
8
8
 
9
9
  DOMPurify is written in JavaScript and works in all modern browsers (Safari (10+), Opera (15+), Edge, Firefox and Chrome - as well as almost anything else using Blink, Gecko or WebKit). It doesn't break on MSIE or other legacy browsers. It simply does nothing.
10
10
 
11
11
  **Note that [DOMPurify v2.5.8](https://github.com/cure53/DOMPurify/releases/tag/2.5.8) is the latest version supporting MSIE. For important security updates compatible with MSIE, please use the [2.x branch](https://github.com/cure53/DOMPurify/tree/2.x).**
12
12
 
13
- Our automated tests cover [28 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 v18.x, v19.x, v20.x, v21.x, v12.x and v23.x, running DOMPurify on [jsdom](https://github.com/jsdom/jsdom). Older Node versions are known to work as well, but hey... no guarantees.
13
+ Our automated tests cover [28 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 v18.x, v19.x, v20.x, v21.x, v22.x and v23.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
 
@@ -22,10 +22,10 @@ DOMPurify sanitizes HTML and prevents XSS attacks. You can feed DOMPurify with s
22
22
 
23
23
  It's easy. Just include DOMPurify on your website.
24
24
 
25
- ### Using the unminified development version
25
+ ### Using the unminified version (source-map available)
26
26
 
27
27
  ```html
28
- <script type="text/javascript" src="src/purify.js"></script>
28
+ <script type="text/javascript" src="dist/purify.js"></script>
29
29
  ```
30
30
 
31
31
  ### Using the minified and tested production version (source-map available)
@@ -303,7 +303,7 @@ const clean = DOMPurify.sanitize(dirty, {
303
303
  TRUSTED_TYPES_POLICY: trustedTypes.createPolicy({
304
304
  createHTML(s) { return s},
305
305
  createScriptURL(s) { return s},
306
- }
306
+ })
307
307
  });
308
308
  ```
309
309
  ### Influence how we sanitize
@@ -385,7 +385,7 @@ DOMPurify.addHook(
385
385
 
386
386
  We are currently using Github Actions in combination with BrowserStack. This gives us the possibility to confirm for each and every commit that all is going according to plan in all supported browsers. Check out the build logs here: https://github.com/cure53/DOMPurify/actions
387
387
 
388
- You can further run local tests by executing `npm test`. The tests work fine with Node.js v0.6.2 and jsdom@8.5.0.
388
+ You can further run local tests by executing `npm run test`.
389
389
 
390
390
  All relevant commits will be signed with the key `0x24BB6BF4` for additional security (since 8th of April 2016).
391
391
 
@@ -1,4 +1,4 @@
1
- /*! @license DOMPurify 3.2.5 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.2.5/LICENSE */
1
+ /*! @license DOMPurify 3.2.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.2.6/LICENSE */
2
2
 
3
3
  import { TrustedTypePolicy, TrustedHTML, TrustedTypesWindow } from 'trusted-types/lib';
4
4
 
@@ -1,4 +1,4 @@
1
- /*! @license DOMPurify 3.2.5 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.2.5/LICENSE */
1
+ /*! @license DOMPurify 3.2.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.2.6/LICENSE */
2
2
 
3
3
  'use strict';
4
4
 
@@ -204,7 +204,7 @@ const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
204
204
  const TMPLIT_EXPR = seal(/\$\{[\w\W]*/gm); // eslint-disable-line unicorn/better-regex
205
205
  const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
206
206
  const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
207
- const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
207
+ const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
208
208
  );
209
209
  const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
210
210
  const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
@@ -301,7 +301,7 @@ const _createHooksMap = function _createHooksMap() {
301
301
  function createDOMPurify() {
302
302
  let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
303
303
  const DOMPurify = root => createDOMPurify(root);
304
- DOMPurify.version = '3.2.5';
304
+ DOMPurify.version = '3.2.6';
305
305
  DOMPurify.removed = [];
306
306
  if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
307
307
  // Not running in a browser, provide a factory function
@@ -540,8 +540,8 @@ function createDOMPurify() {
540
540
  URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR, transformCaseFunc) : DEFAULT_URI_SAFE_ATTRIBUTES;
541
541
  DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS, transformCaseFunc) : DEFAULT_DATA_URI_TAGS;
542
542
  FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
543
- FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
544
- FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
543
+ FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : clone({});
544
+ FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : clone({});
545
545
  USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false;
546
546
  ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
547
547
  ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
@@ -906,7 +906,7 @@ function createDOMPurify() {
906
906
  allowedTags: ALLOWED_TAGS
907
907
  });
908
908
  /* Detect mXSS attempts abusing namespace confusion */
909
- if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\w!]/g, currentNode.innerHTML) && regExpTest(/<[/\w!]/g, currentNode.textContent)) {
909
+ if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\w!]/g, currentNode.innerHTML) && regExpTest(/<[/\w!]/g, currentNode.textContent)) {
910
910
  _forceRemove(currentNode);
911
911
  return true;
912
912
  }
@@ -1058,7 +1058,8 @@ function createDOMPurify() {
1058
1058
  value: attrValue
1059
1059
  } = attr;
1060
1060
  const lcName = transformCaseFunc(name);
1061
- let value = name === 'value' ? attrValue : stringTrim(attrValue);
1061
+ const initValue = attrValue;
1062
+ let value = name === 'value' ? initValue : stringTrim(initValue);
1062
1063
  /* Execute a hook if present */
1063
1064
  hookEvent.attrName = lcName;
1064
1065
  hookEvent.attrValue = value;
@@ -1084,10 +1085,9 @@ function createDOMPurify() {
1084
1085
  if (hookEvent.forceKeepAttr) {
1085
1086
  continue;
1086
1087
  }
1087
- /* Remove attribute */
1088
- _removeAttribute(name, currentNode);
1089
1088
  /* Did the hooks approve of the attribute? */
1090
1089
  if (!hookEvent.keepAttr) {
1090
+ _removeAttribute(name, currentNode);
1091
1091
  continue;
1092
1092
  }
1093
1093
  /* Work around a security issue in jQuery 3.0 */
@@ -1104,6 +1104,7 @@ function createDOMPurify() {
1104
1104
  /* Is `value` valid for this attribute? */
1105
1105
  const lcTag = transformCaseFunc(currentNode.nodeName);
1106
1106
  if (!_isValidAttribute(lcTag, lcName, value)) {
1107
+ _removeAttribute(name, currentNode);
1107
1108
  continue;
1108
1109
  }
1109
1110
  /* Handle attributes that require Trusted Types */
@@ -1124,19 +1125,23 @@ function createDOMPurify() {
1124
1125
  }
1125
1126
  }
1126
1127
  /* Handle invalid data-* attribute set by try-catching it */
1127
- try {
1128
- if (namespaceURI) {
1129
- currentNode.setAttributeNS(namespaceURI, name, value);
1130
- } else {
1131
- /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
1132
- currentNode.setAttribute(name, value);
1133
- }
1134
- if (_isClobbered(currentNode)) {
1135
- _forceRemove(currentNode);
1136
- } else {
1137
- arrayPop(DOMPurify.removed);
1128
+ if (value !== initValue) {
1129
+ try {
1130
+ if (namespaceURI) {
1131
+ currentNode.setAttributeNS(namespaceURI, name, value);
1132
+ } else {
1133
+ /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
1134
+ currentNode.setAttribute(name, value);
1135
+ }
1136
+ if (_isClobbered(currentNode)) {
1137
+ _forceRemove(currentNode);
1138
+ } else {
1139
+ arrayPop(DOMPurify.removed);
1140
+ }
1141
+ } catch (_) {
1142
+ _removeAttribute(name, currentNode);
1138
1143
  }
1139
- } catch (_) {}
1144
+ }
1140
1145
  }
1141
1146
  /* Execute a hook if present */
1142
1147
  _executeHooks(hooks.afterSanitizeAttributes, currentNode, null);