Skip to content

Commit 3ad7750

Browse files
committed
Make TAG and ATTR cfg options case-sensitive when parsing XHTML
1 parent 87b29de commit 3ad7750

File tree

3 files changed

+60
-25
lines changed

3 files changed

+60
-25
lines changed

src/purify.js

+37-23
Original file line numberDiff line numberDiff line change
@@ -380,29 +380,55 @@ function createDOMPurify(window = getGlobal()) {
380380
/* Shield configuration object from prototype pollution */
381381
cfg = clone(cfg);
382382

383+
PARSER_MEDIA_TYPE =
384+
// eslint-disable-next-line unicorn/prefer-includes
385+
SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1
386+
? (PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE)
387+
: (PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE);
388+
389+
// HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
390+
transformCaseFunc =
391+
PARSER_MEDIA_TYPE === 'application/xhtml+xml'
392+
? (x) => x
393+
: stringToLowerCase;
394+
383395
/* Set configuration parameters */
384396
ALLOWED_TAGS =
385397
'ALLOWED_TAGS' in cfg
386-
? addToSet({}, cfg.ALLOWED_TAGS)
398+
? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc)
387399
: DEFAULT_ALLOWED_TAGS;
388400
ALLOWED_ATTR =
389401
'ALLOWED_ATTR' in cfg
390-
? addToSet({}, cfg.ALLOWED_ATTR)
402+
? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc)
391403
: DEFAULT_ALLOWED_ATTR;
392404
URI_SAFE_ATTRIBUTES =
393405
'ADD_URI_SAFE_ATTR' in cfg
394-
? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR)
406+
? addToSet(
407+
clone(DEFAULT_URI_SAFE_ATTRIBUTES),
408+
cfg.ADD_URI_SAFE_ATTR,
409+
transformCaseFunc
410+
)
395411
: DEFAULT_URI_SAFE_ATTRIBUTES;
396412
DATA_URI_TAGS =
397413
'ADD_DATA_URI_TAGS' in cfg
398-
? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS)
414+
? addToSet(
415+
clone(DEFAULT_DATA_URI_TAGS),
416+
cfg.ADD_DATA_URI_TAGS,
417+
transformCaseFunc
418+
)
399419
: DEFAULT_DATA_URI_TAGS;
400420
FORBID_CONTENTS =
401421
'FORBID_CONTENTS' in cfg
402-
? addToSet({}, cfg.FORBID_CONTENTS)
422+
? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc)
403423
: DEFAULT_FORBID_CONTENTS;
404-
FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS) : {};
405-
FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR) : {};
424+
FORBID_TAGS =
425+
'FORBID_TAGS' in cfg
426+
? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc)
427+
: {};
428+
FORBID_ATTR =
429+
'FORBID_ATTR' in cfg
430+
? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc)
431+
: {};
406432
USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
407433
ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
408434
ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
@@ -443,18 +469,6 @@ function createDOMPurify(window = getGlobal()) {
443469
cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
444470
}
445471

446-
PARSER_MEDIA_TYPE =
447-
// eslint-disable-next-line unicorn/prefer-includes
448-
SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1
449-
? (PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE)
450-
: (PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE);
451-
452-
// HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
453-
transformCaseFunc =
454-
PARSER_MEDIA_TYPE === 'application/xhtml+xml'
455-
? (x) => x
456-
: stringToLowerCase;
457-
458472
if (SAFE_FOR_TEMPLATES) {
459473
ALLOW_DATA_ATTR = false;
460474
}
@@ -497,27 +511,27 @@ function createDOMPurify(window = getGlobal()) {
497511
ALLOWED_TAGS = clone(ALLOWED_TAGS);
498512
}
499513

500-
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS);
514+
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
501515
}
502516

503517
if (cfg.ADD_ATTR) {
504518
if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
505519
ALLOWED_ATTR = clone(ALLOWED_ATTR);
506520
}
507521

508-
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR);
522+
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
509523
}
510524

511525
if (cfg.ADD_URI_SAFE_ATTR) {
512-
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR);
526+
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
513527
}
514528

515529
if (cfg.FORBID_CONTENTS) {
516530
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
517531
FORBID_CONTENTS = clone(FORBID_CONTENTS);
518532
}
519533

520-
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS);
534+
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
521535
}
522536

523537
/* Add #text in case KEEP_CONTENT is set to true */

src/utils.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ export function unconstruct(func) {
5858
}
5959

6060
/* Add properties to a lookup table */
61-
export function addToSet(set, array) {
61+
export function addToSet(set, array, transformCaseFunc) {
62+
transformCaseFunc = transformCaseFunc ? transformCaseFunc : stringToLowerCase;
6263
if (setPrototypeOf) {
6364
// Make 'in' and truthy checks like Boolean(set.constructor)
6465
// independent of any properties defined on Object.prototype.
@@ -70,7 +71,7 @@ export function addToSet(set, array) {
7071
while (l--) {
7172
let element = array[l];
7273
if (typeof element === 'string') {
73-
const lcElement = stringToLowerCase(element);
74+
const lcElement = transformCaseFunc(element);
7475
if (lcElement !== element) {
7576
// Config presets (e.g. tags.js, attrs.js) are immutable.
7677
if (!isFrozen(array)) {

test/test-suite.js

+20
Original file line numberDiff line numberDiff line change
@@ -1842,6 +1842,26 @@
18421842
});
18431843
});
18441844

1845+
QUnit.test(
1846+
'Config-Flag tests: PARSER_MEDIA_TYPE + ALLOWED_TAGS/ALLOWED_ATTR',
1847+
function (assert) {
1848+
assert.contains(
1849+
DOMPurify.sanitize(
1850+
'<a href="#">abc</a><CustomTag customattr="bar" CustomAttr="foo"/>',
1851+
{
1852+
PARSER_MEDIA_TYPE: 'application/xhtml+xml',
1853+
ALLOWED_TAGS: ['a', 'CustomTag'],
1854+
ALLOWED_ATTR: ['href', 'CustomAttr'],
1855+
}
1856+
),
1857+
[
1858+
'<a xmlns="http://www.w3.org/1999/xhtml" href="#">abc</a>' +
1859+
'<CustomTag xmlns="http://www.w3.org/1999/xhtml" CustomAttr="foo"></CustomTag>',
1860+
]
1861+
);
1862+
}
1863+
);
1864+
18451865
QUnit.test('Test invalid xml', function (assert) {
18461866
var tests = [
18471867
{

0 commit comments

Comments
 (0)