Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ const clean = DOMPurify.sanitize(dirty, {SAFE_FOR_TEMPLATES: true});


// change how e.g. comments containing risky HTML characters are treated.
// be very careful, this setting should only be set to `false` if you really only handle
// HTML and nothing else, no SVG, MathML or the like.
// be very careful, this setting should only be set to `false` if you really only handle
// HTML and nothing else, no SVG, MathML or the like.
// Otherwise, changing from `true` to `false` will lead to XSS in this or some other way.
const clean = DOMPurify.sanitize(dirty, {SAFE_FOR_XML: false});
```
Expand Down Expand Up @@ -215,6 +215,24 @@ const clean = DOMPurify.sanitize(dirty, {ADD_TAGS: ['my-tag']});
// extend the existing array of allowed attributes and add my-attr to allow-list
const clean = DOMPurify.sanitize(dirty, {ADD_ATTR: ['my-attr']});

// use functions to control which additional tags and attributes are allowed
const allowlist = {
'one': ['attribute-one'],
'two': ['attribute-two']
};
const clean = DOMPurify.sanitize(
'<one attribute-one="1" attribute-two="2"></one><two attribute-one="1" attribute-two="2"></two>',
{
ADD_TAGS: (tagName) => {
return Object.keys(allowlist).includes(tagName);
},
ADD_ATTR: (attributeName, tagName) => {

return allowlist[tagName]?.includes(attributeName) || false;
}
}
); // <one attribute-one="1"></one><two attribute-two="2"></two>

// prohibit ARIA attributes, leave other safe HTML as is (default is true)
const clean = DOMPurify.sanitize(dirty, {ALLOW_ARIA_ATTR: false});

Expand Down
8 changes: 6 additions & 2 deletions dist/purify.cjs.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,20 @@ import { TrustedTypePolicy, TrustedHTML, TrustedTypesWindow } from 'trusted-type
interface Config {
/**
* Extend the existing array of allowed attributes.
* Can be an array of attribute names, or a function that receives
* the attribute name and tag name to determine if the attribute is allowed.
*/
ADD_ATTR?: string[] | undefined;
ADD_ATTR?: string[] | ((attributeName: string, tagName: string) => boolean) | undefined;
/**
* Extend the existing array of elements that can use Data URIs.
*/
ADD_DATA_URI_TAGS?: string[] | undefined;
/**
* Extend the existing array of allowed tags.
* Can be an array of tag names, or a function that receives
* the tag name to determine if the tag is allowed.
*/
ADD_TAGS?: string[] | undefined;
ADD_TAGS?: string[] | ((tagName: string) => boolean) | undefined;
/**
* Extend the existing array of elements that are safe for URI-like values (be careful, XSS risk).
*/
Expand Down
39 changes: 31 additions & 8 deletions dist/purify.cjs.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/purify.cjs.js.map

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions dist/purify.es.d.mts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,20 @@ import { TrustedTypePolicy, TrustedHTML, TrustedTypesWindow } from 'trusted-type
interface Config {
/**
* Extend the existing array of allowed attributes.
* Can be an array of attribute names, or a function that receives
* the attribute name and tag name to determine if the attribute is allowed.
*/
ADD_ATTR?: string[] | undefined;
ADD_ATTR?: string[] | ((attributeName: string, tagName: string) => boolean) | undefined;
/**
* Extend the existing array of elements that can use Data URIs.
*/
ADD_DATA_URI_TAGS?: string[] | undefined;
/**
* Extend the existing array of allowed tags.
* Can be an array of tag names, or a function that receives
* the tag name to determine if the tag is allowed.
*/
ADD_TAGS?: string[] | undefined;
ADD_TAGS?: string[] | ((tagName: string) => boolean) | undefined;
/**
* Extend the existing array of elements that are safe for URI-like values (be careful, XSS risk).
*/
Expand Down
39 changes: 31 additions & 8 deletions dist/purify.es.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,21 @@ function createDOMPurify() {
let FORBID_TAGS = null;
/* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
let FORBID_ATTR = null;
/* Config object to store ADD_TAGS/ADD_ATTR functions (when used as functions) */
const EXTRA_ELEMENT_HANDLING = Object.seal(create(null, {
tagCheck: {
writable: true,
configurable: false,
enumerable: true,
value: null
},
attributeCheck: {
writable: true,
configurable: false,
enumerable: true,
value: null
}
}));
/* Decide if ARIA attributes are okay */
let ALLOW_ARIA_ATTR = true;
/* Decide if custom data attributes are okay */
Expand Down Expand Up @@ -608,16 +623,24 @@ function createDOMPurify() {
}
/* Merge configuration parameters */
if (cfg.ADD_TAGS) {
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
ALLOWED_TAGS = clone(ALLOWED_TAGS);
if (typeof cfg.ADD_TAGS === 'function') {
EXTRA_ELEMENT_HANDLING.tagCheck = cfg.ADD_TAGS;
} else {
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
ALLOWED_TAGS = clone(ALLOWED_TAGS);
}
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
}
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
}
if (cfg.ADD_ATTR) {
if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
ALLOWED_ATTR = clone(ALLOWED_ATTR);
if (typeof cfg.ADD_ATTR === 'function') {
EXTRA_ELEMENT_HANDLING.attributeCheck = cfg.ADD_ATTR;
} else {
if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
ALLOWED_ATTR = clone(ALLOWED_ATTR);
}
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
}
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
}
if (cfg.ADD_URI_SAFE_ATTR) {
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
Expand Down Expand Up @@ -925,7 +948,7 @@ function createDOMPurify() {
return true;
}
/* Remove element if anything forbids its presence */
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
if (!(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName])) {
/* Check if we have a custom element to handle */
if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
Expand Down Expand Up @@ -997,7 +1020,7 @@ function createDOMPurify() {
(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
We don't need to check the value; it's always URI safe. */
if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
if (
// First condition does a very basic check if a) it's basically a valid custom element tagname AND
// b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
Expand Down
2 changes: 1 addition & 1 deletion dist/purify.es.mjs.map

Large diffs are not rendered by default.

39 changes: 31 additions & 8 deletions dist/purify.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/purify.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/purify.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/purify.min.js.map

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ import type { TrustedTypePolicy } from 'trusted-types/lib';
export interface Config {
/**
* Extend the existing array of allowed attributes.
* Can be an array of attribute names, or a function that receives
* the attribute name and tag name to determine if the attribute is allowed.
*/
ADD_ATTR?: string[] | undefined;
ADD_ATTR?:
| string[]
| ((attributeName: string, tagName: string) => boolean)
| undefined;

/**
* Extend the existing array of elements that can use Data URIs.
Expand All @@ -18,8 +23,10 @@ export interface Config {

/**
* Extend the existing array of allowed tags.
* Can be an array of tag names, or a function that receives
* the tag name to determine if the tag is allowed.
*/
ADD_TAGS?: string[] | undefined;
ADD_TAGS?: string[] | ((tagName: string) => boolean) | undefined;

/**
* Extend the existing array of elements that are safe for URI-like values (be careful, XSS risk).
Expand Down
Loading
Loading