dompurify 3.1.1 → 3.1.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 +3 -3
- package/dist/purify.cjs.js +57 -20
- package/dist/purify.cjs.js.map +1 -1
- package/dist/purify.es.mjs +57 -20
- package/dist/purify.es.mjs.map +1 -1
- package/dist/purify.js +57 -20
- package/dist/purify.js.map +1 -1
- package/dist/purify.min.js +2 -2
- package/dist/purify.min.js.map +1 -1
- package/package.json +1 -1
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 **v3.1.
|
|
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 **v3.1.3**.
|
|
10
10
|
|
|
11
11
|
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.
|
|
12
12
|
|
|
13
|
-
**Note that [DOMPurify v2.5.
|
|
13
|
+
**Note that [DOMPurify v2.5.3](https://github.com/cure53/DOMPurify/releases/tag/2.5.3) 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).**
|
|
14
14
|
|
|
15
15
|
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 v16.x, v17.x, v18.x and v19.x, running DOMPurify on [jsdom](https://github.com/jsdom/jsdom). Older Node versions are known to work as well, but hey... no guarantees.
|
|
16
16
|
|
|
@@ -424,7 +424,7 @@ Feature releases will not be announced to this list.
|
|
|
424
424
|
|
|
425
425
|
Many people helped and help DOMPurify become what it is and need to be acknowledged here!
|
|
426
426
|
|
|
427
|
-
[dcramer 💸](https://github.com/dcramer), [JGraph 💸](https://github.com/jgraph), [baekilda 💸](https://github.com/baekilda), [Healthchecks 💸](https://github.com/healthchecks), [Sentry 💸](https://github.com/getsentry), [jarrodldavis 💸](https://github.com/jarrodldavis), [CynegeticIO](https://github.com/CynegeticIO), [ssi02014 ❤️](https://github.com/ssi02014), [
|
|
427
|
+
[hash_kitten ❤️](https://twitter.com/hash_kitten), [kevin_mizu ❤️](https://twitter.com/kevin_mizu), [icesfont ❤️](https://github.com/icesfont) [dcramer 💸](https://github.com/dcramer), [JGraph 💸](https://github.com/jgraph), [baekilda 💸](https://github.com/baekilda), [Healthchecks 💸](https://github.com/healthchecks), [Sentry 💸](https://github.com/getsentry), [jarrodldavis 💸](https://github.com/jarrodldavis), [CynegeticIO](https://github.com/CynegeticIO), [ssi02014 ❤️](https://github.com/ssi02014), [GrantGryczan](https://github.com/GrantGryczan), [Lowdefy](https://twitter.com/lowdefy), [granlem](https://twitter.com/MaximeVeit), [oreoshake](https://github.com/oreoshake), [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)
|
|
428
428
|
|
|
429
429
|
## Testing powered by
|
|
430
430
|
|
package/dist/purify.cjs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @license DOMPurify 3.1.
|
|
1
|
+
/*! @license DOMPurify 3.1.3 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.3/LICENSE */
|
|
2
2
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
@@ -50,6 +50,7 @@ const stringTrim = unapply(String.prototype.trim);
|
|
|
50
50
|
const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
|
|
51
51
|
const regExpTest = unapply(RegExp.prototype.test);
|
|
52
52
|
const typeErrorCreate = unconstruct(TypeError);
|
|
53
|
+
const numberIsNaN = unapply(Number.isNaN);
|
|
53
54
|
|
|
54
55
|
/**
|
|
55
56
|
* Creates a new function that calls the given function with a specified thisArg and arguments.
|
|
@@ -233,6 +234,24 @@ var EXPRESSIONS = /*#__PURE__*/Object.freeze({
|
|
|
233
234
|
CUSTOM_ELEMENT: CUSTOM_ELEMENT
|
|
234
235
|
});
|
|
235
236
|
|
|
237
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
|
|
238
|
+
const NODE_TYPE = {
|
|
239
|
+
element: 1,
|
|
240
|
+
attribute: 2,
|
|
241
|
+
text: 3,
|
|
242
|
+
cdataSection: 4,
|
|
243
|
+
entityReference: 5,
|
|
244
|
+
// Deprecated
|
|
245
|
+
entityNode: 6,
|
|
246
|
+
// Deprecated
|
|
247
|
+
progressingInstruction: 7,
|
|
248
|
+
comment: 8,
|
|
249
|
+
document: 9,
|
|
250
|
+
documentType: 10,
|
|
251
|
+
documentFragment: 11,
|
|
252
|
+
notation: 12 // Deprecated
|
|
253
|
+
};
|
|
254
|
+
|
|
236
255
|
const getGlobal = function getGlobal() {
|
|
237
256
|
return typeof window === 'undefined' ? null : window;
|
|
238
257
|
};
|
|
@@ -284,14 +303,14 @@ function createDOMPurify() {
|
|
|
284
303
|
* Version label, exposed for easier checks
|
|
285
304
|
* if DOMPurify is up to date or not
|
|
286
305
|
*/
|
|
287
|
-
DOMPurify.version = '3.1.
|
|
306
|
+
DOMPurify.version = '3.1.3';
|
|
288
307
|
|
|
289
308
|
/**
|
|
290
309
|
* Array of elements that DOMPurify removed during sanitation.
|
|
291
310
|
* Empty if nothing was removed.
|
|
292
311
|
*/
|
|
293
312
|
DOMPurify.removed = [];
|
|
294
|
-
if (!window || !window.document || window.document.nodeType !==
|
|
313
|
+
if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document) {
|
|
295
314
|
// Not running in a browser, provide a factory function
|
|
296
315
|
// so that you can pass your own Window
|
|
297
316
|
DOMPurify.isSupported = false;
|
|
@@ -706,7 +725,7 @@ function createDOMPurify() {
|
|
|
706
725
|
CONFIG = cfg;
|
|
707
726
|
};
|
|
708
727
|
const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
|
|
709
|
-
const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', '
|
|
728
|
+
const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'annotation-xml']);
|
|
710
729
|
|
|
711
730
|
// Certain elements are allowed in both SVG and HTML
|
|
712
731
|
// namespace. We need to specify them explicitly
|
|
@@ -1002,13 +1021,13 @@ function createDOMPurify() {
|
|
|
1002
1021
|
}
|
|
1003
1022
|
|
|
1004
1023
|
/* Remove any ocurrence of processing instructions */
|
|
1005
|
-
if (currentNode.nodeType ===
|
|
1024
|
+
if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
|
|
1006
1025
|
_forceRemove(currentNode);
|
|
1007
1026
|
return true;
|
|
1008
1027
|
}
|
|
1009
1028
|
|
|
1010
1029
|
/* Remove any kind of possibly harmful comments */
|
|
1011
|
-
if (SAFE_FOR_XML && currentNode.nodeType ===
|
|
1030
|
+
if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\w]/g, currentNode.data)) {
|
|
1012
1031
|
_forceRemove(currentNode);
|
|
1013
1032
|
return true;
|
|
1014
1033
|
}
|
|
@@ -1055,7 +1074,7 @@ function createDOMPurify() {
|
|
|
1055
1074
|
}
|
|
1056
1075
|
|
|
1057
1076
|
/* Sanitize element content to be template-safe */
|
|
1058
|
-
if (SAFE_FOR_TEMPLATES && currentNode.nodeType ===
|
|
1077
|
+
if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
|
|
1059
1078
|
/* Get the element's text content */
|
|
1060
1079
|
content = currentNode.textContent;
|
|
1061
1080
|
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
|
@@ -1085,7 +1104,7 @@ function createDOMPurify() {
|
|
|
1085
1104
|
// eslint-disable-next-line complexity
|
|
1086
1105
|
const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
|
|
1087
1106
|
/* Make sure attribute cannot clobber */
|
|
1088
|
-
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
|
|
1107
|
+
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement || value === '__depth' || value === '__removalCount')) {
|
|
1089
1108
|
return false;
|
|
1090
1109
|
}
|
|
1091
1110
|
|
|
@@ -1189,6 +1208,12 @@ function createDOMPurify() {
|
|
|
1189
1208
|
continue;
|
|
1190
1209
|
}
|
|
1191
1210
|
|
|
1211
|
+
/* Work around a security issue with comments inside attributes */
|
|
1212
|
+
if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title)/i, value)) {
|
|
1213
|
+
_removeAttribute(name, currentNode);
|
|
1214
|
+
continue;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1192
1217
|
/* Sanitize attribute content to be template-safe */
|
|
1193
1218
|
if (SAFE_FOR_TEMPLATES) {
|
|
1194
1219
|
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
|
@@ -1239,7 +1264,11 @@ function createDOMPurify() {
|
|
|
1239
1264
|
/* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
|
|
1240
1265
|
currentNode.setAttribute(name, value);
|
|
1241
1266
|
}
|
|
1242
|
-
|
|
1267
|
+
if (_isClobbered(currentNode)) {
|
|
1268
|
+
_forceRemove(currentNode);
|
|
1269
|
+
} else {
|
|
1270
|
+
arrayPop(DOMPurify.removed);
|
|
1271
|
+
}
|
|
1243
1272
|
} catch (_) {}
|
|
1244
1273
|
}
|
|
1245
1274
|
|
|
@@ -1266,22 +1295,26 @@ function createDOMPurify() {
|
|
|
1266
1295
|
if (_sanitizeElements(shadowNode)) {
|
|
1267
1296
|
continue;
|
|
1268
1297
|
}
|
|
1298
|
+
const parentNode = getParentNode(shadowNode);
|
|
1269
1299
|
|
|
1270
1300
|
/* Set the nesting depth of an element */
|
|
1271
|
-
if (shadowNode.nodeType ===
|
|
1272
|
-
if (
|
|
1301
|
+
if (shadowNode.nodeType === NODE_TYPE.element) {
|
|
1302
|
+
if (parentNode && parentNode.__depth) {
|
|
1273
1303
|
/*
|
|
1274
1304
|
We want the depth of the node in the original tree, which can
|
|
1275
1305
|
change when it's removed from its parent.
|
|
1276
1306
|
*/
|
|
1277
|
-
shadowNode.__depth = (shadowNode.__removalCount || 0) +
|
|
1307
|
+
shadowNode.__depth = (shadowNode.__removalCount || 0) + parentNode.__depth + 1;
|
|
1278
1308
|
} else {
|
|
1279
1309
|
shadowNode.__depth = 1;
|
|
1280
1310
|
}
|
|
1281
1311
|
}
|
|
1282
1312
|
|
|
1283
|
-
/*
|
|
1284
|
-
|
|
1313
|
+
/*
|
|
1314
|
+
* Remove an element if nested too deeply to avoid mXSS
|
|
1315
|
+
* or if the __depth might have been tampered with
|
|
1316
|
+
*/
|
|
1317
|
+
if (shadowNode.__depth >= MAX_NESTING_DEPTH || shadowNode.__depth < 0 || numberIsNaN(shadowNode.__depth)) {
|
|
1285
1318
|
_forceRemove(shadowNode);
|
|
1286
1319
|
}
|
|
1287
1320
|
|
|
@@ -1363,7 +1396,7 @@ function createDOMPurify() {
|
|
|
1363
1396
|
elements being stripped by the parser */
|
|
1364
1397
|
body = _initDocument('<!---->');
|
|
1365
1398
|
importedNode = body.ownerDocument.importNode(dirty, true);
|
|
1366
|
-
if (importedNode.nodeType ===
|
|
1399
|
+
if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === 'BODY') {
|
|
1367
1400
|
/* Node is already a body, use as is */
|
|
1368
1401
|
body = importedNode;
|
|
1369
1402
|
} else if (importedNode.nodeName === 'HTML') {
|
|
@@ -1403,22 +1436,26 @@ function createDOMPurify() {
|
|
|
1403
1436
|
if (_sanitizeElements(currentNode)) {
|
|
1404
1437
|
continue;
|
|
1405
1438
|
}
|
|
1439
|
+
const parentNode = getParentNode(currentNode);
|
|
1406
1440
|
|
|
1407
1441
|
/* Set the nesting depth of an element */
|
|
1408
|
-
if (currentNode.nodeType ===
|
|
1409
|
-
if (
|
|
1442
|
+
if (currentNode.nodeType === NODE_TYPE.element) {
|
|
1443
|
+
if (parentNode && parentNode.__depth) {
|
|
1410
1444
|
/*
|
|
1411
1445
|
We want the depth of the node in the original tree, which can
|
|
1412
1446
|
change when it's removed from its parent.
|
|
1413
1447
|
*/
|
|
1414
|
-
currentNode.__depth = (currentNode.__removalCount || 0) +
|
|
1448
|
+
currentNode.__depth = (currentNode.__removalCount || 0) + parentNode.__depth + 1;
|
|
1415
1449
|
} else {
|
|
1416
1450
|
currentNode.__depth = 1;
|
|
1417
1451
|
}
|
|
1418
1452
|
}
|
|
1419
1453
|
|
|
1420
|
-
/*
|
|
1421
|
-
|
|
1454
|
+
/*
|
|
1455
|
+
* Remove an element if nested too deeply to avoid mXSS
|
|
1456
|
+
* or if the __depth might have been tampered with
|
|
1457
|
+
*/
|
|
1458
|
+
if (currentNode.__depth >= MAX_NESTING_DEPTH || currentNode.__depth < 0 || numberIsNaN(currentNode.__depth)) {
|
|
1422
1459
|
_forceRemove(currentNode);
|
|
1423
1460
|
}
|
|
1424
1461
|
|