Socket
Socket
Sign inDemoInstall

dompurify

Package Overview
Dependencies
0
Maintainers
2
Versions
118
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.6.7 to 0.7.0

dist/purify.min.js

2

bower.json
{
"name": "DOMPurify",
"version": "0.6.7",
"version": "0.7.0",
"homepage": "https://github.com/cure53/DOMPurify",

@@ -5,0 +5,0 @@ "author": "Cure53 <info@cure53.de>",

@@ -57,6 +57,6 @@ ## What is this?

// Add a hook to convert all text to capitals
DOMPurify.addHook('beforeSanitizeAttributes', function(node){
DOMPurify.addHook('beforeSanitizeAttributes', function(node) {
// Set text node content to uppercase
if(node.nodeName && node.nodeName === '#text') {
node.textContent=node.textContent.toUpperCase();
if (node.nodeName && node.nodeName === '#text') {
node.textContent = node.textContent.toUpperCase();
}

@@ -76,6 +76,6 @@ });

// Add a hook to convert all text to capitals
DOMPurify.addHook('beforeSanitizeAttributes', function(node){
DOMPurify.addHook('beforeSanitizeAttributes', function(node) {
// Set text node content to uppercase
if(node.nodeName && node.nodeName === '#text') {
node.textContent=node.textContent.toUpperCase();
if (node.nodeName && node.nodeName === '#text') {
node.textContent = node.textContent.toUpperCase();
}

@@ -101,11 +101,11 @@ });

// Add a hook to make all links open a new window
DOMPurify.addHook('afterSanitizeAttributes', function(node){
DOMPurify.addHook('afterSanitizeAttributes', function(node) {
// set all elements owning target to target=_blank
if('target' in node){
if ('target' in node) {
node.setAttribute('target','_blank');
}
// set non-HTML/MathML links to xlink:show=new
if(!node.hasAttribute('target')
if (!node.hasAttribute('target')
&& (node.hasAttribute('xlink:href')
|| node.hasAttribute('href'))){
|| node.hasAttribute('href'))) {
node.setAttribute('xlink:show', 'new');

@@ -131,6 +131,6 @@ }

// build fitting regex
var regex = RegExp('^('+whitelist.join('|')+'):', 'gim');
var regex = RegExp('^(' + whitelist.join('|') + '):', 'gim');
// Add a hook to enforce URI scheme whitelist
DOMPurify.addHook('afterSanitizeAttributes', function(node){
DOMPurify.addHook('afterSanitizeAttributes', function(node) {

@@ -141,5 +141,5 @@ // build an anchor to map URLs to

// check all href attributes for validity
if(node.hasAttribute('href')){
if (node.hasAttribute('href')) {
anchor.href = node.getAttribute('href');
if(anchor.protocol && !anchor.protocol.match(regex)){
if (anchor.protocol && !anchor.protocol.match(regex)) {
node.removeAttribute('href');

@@ -149,5 +149,5 @@ }

// check all action attributes for validity
if(node.hasAttribute('action')){
if (node.hasAttribute('action')) {
anchor.href = node.getAttribute('action');
if(anchor.protocol && !anchor.protocol.match(regex)){
if (anchor.protocol && !anchor.protocol.match(regex)) {
node.removeAttribute('action');

@@ -157,5 +157,5 @@ }

// check all xlink:href attributes for validity
if(node.hasAttribute('xlink:href')){
if (node.hasAttribute('xlink:href')) {
anchor.href = node.getAttribute('xlink:href');
if(anchor.protocol && !anchor.protocol.match(regex)){
if (anchor.protocol && !anchor.protocol.match(regex)) {
node.removeAttribute('xlink:href');

@@ -185,8 +185,8 @@ }

// Add a hook to sanitize all script content with MentalJS
DOMPurify.addHook('uponSanitizeElement', function(node, data){
if(data.tagName === 'script'){
DOMPurify.addHook('uponSanitizeElement', function(node, data) {
if (data.tagName === 'script') {
var script = node.textContent;
if(!script || 'src' in node.attributes
if (!script || 'src' in node.attributes
|| 'href' in node.attributes
|| 'xlink:href' in node.attributes){
|| 'xlink:href' in node.attributes) {
return node.parentNode.removeChild(node)

@@ -196,3 +196,9 @@ }

var mental = MentalJS().parse(
{options:{eval:false, dom:true}, code:script}
{
options: {
eval: false,
dom:true
},
code:script
}
);

@@ -207,8 +213,14 @@ return node.textContent = mental;

// Add a hook to sanitize all white-listed events with MentalJS
DOMPurify.addHook('uponSanitizeAttribute', function(node, data){
if(data.attrName.match(/^on\w+/)) {
DOMPurify.addHook('uponSanitizeAttribute', function(node, data) {
if (data.attrName.match(/^on\w+/)) {
var script = data.attrValue;
try {
return data.attrValue = MentalJS().parse(
{options:{eval:false, dom:true}, code:script}
{
options: {
eval: false,
dom:true
},
code:script
}
);

@@ -232,5 +244,5 @@ } catch(e) {

// Add a hook to make all links point to a proxy
DOMPurify.addHook('afterSanitizeAttributes', function(node){
DOMPurify.addHook('afterSanitizeAttributes', function(node) {
// proxy form actions
if('action' in node){
if ('action' in node) {
node.setAttribute('action', proxy

@@ -240,3 +252,3 @@ + encodeURIComponent(node.getAttribute('action')));

// proxy regular HTML links
if(node.hasAttribute('href')){
if (node.hasAttribute('href')) {
node.setAttribute('href', proxy

@@ -246,3 +258,3 @@ + encodeURIComponent(node.getAttribute('href')));

// proxy SVG/MathML links
if(node.hasAttribute('xlink:href')){
if (node.hasAttribute('xlink:href')) {
node.setAttribute('xlink:href', proxy

@@ -285,9 +297,9 @@ + encodeURIComponent(node.getAttribute('xlink:href')));

function addStyles(output, styles) {
for (var prop=styles.length-1; prop>=0; prop--) {
if(styles[styles[prop]]){
var url = styles[styles[prop]].replace(regex, '$1'+proxy);
styles[styles[prop]]=url;
for (var prop = styles.length-1; prop >= 0; prop--) {
if (styles[styles[prop]]) {
var url = styles[styles[prop]].replace(regex, '$1' + proxy);
styles[styles[prop]] = url;
}
if(styles[styles[prop]]) {
output.push(styles[prop]+':'+styles[styles[prop]]+';');
if (styles[styles[prop]]) {
output.push(styles[prop] + ':' + styles[styles[prop]] + ';');
}

@@ -302,6 +314,6 @@ }

function addCSSRules(output, cssRules) {
for (var index=cssRules.length-1; index>=0; index--) {
for (var index = cssRules.length-1; index >= 0; index--) {
var rule = cssRules[index];
// check for rules with selector
if (rule.type == 1 && rule.selectorText){
if (rule.type == 1 && rule.selectorText) {
output.push(rule.selectorText + '{')

@@ -327,3 +339,3 @@ if (rule.style) {

output.push('@keyframes ' + rule.name + '{');
for (var i=rule.cssRules.length-1;i>=0;i--) {
for (var i=rule.cssRules.length-1; i>=0; i--) {
var frame = rule.cssRules[i];

@@ -355,3 +367,3 @@ if (frame.type === 8 && frame.keyText) {

// Add a hook to enforce proxy for leaky CSS rules
DOMPurify.addHook('uponSanitizeElement', function (node, data) {
DOMPurify.addHook('uponSanitizeElement', function(node, data) {
if (data.tagName === 'style') {

@@ -365,9 +377,9 @@ var output = [];

// Add a hook to enforce proxy for all HTTP leaks incl. inline CSS
DOMPurify.addHook('afterSanitizeAttributes', function(node){
DOMPurify.addHook('afterSanitizeAttributes', function(node) {
// Check all src attributes and proxy them
for(var i = 0; i<=attributes.length-1; i++){
if(node.hasAttribute(attributes[i])){
for(var i = 0; i <= attributes.length-1; i++) {
if (node.hasAttribute(attributes[i])) {
node.setAttribute(attributes[i], proxyAttribute(
node.getAttribute(attributes[i]))
node.getAttribute(attributes[i]))
);

@@ -378,15 +390,15 @@ }

// Check all style attribute values and proxy them
if(node.hasAttribute('style')){
if (node.hasAttribute('style')) {
var styles = node.style;
var output = [];
for(var prop=styles.length-1; prop>=0; prop--) {
for(var prop = styles.length-1; prop >= 0; prop--) {
// we re-write each property-value pair to remove invalid CSS
if(node.style[styles[prop]] && regex.test(node.style[styles[prop]])) {
var url = node.style[styles[prop]].replace(regex, '$1'+proxy)
node.style[styles[prop]]=url;
if (node.style[styles[prop]] && regex.test(node.style[styles[prop]])) {
var url = node.style[styles[prop]].replace(regex, '$1' + proxy)
node.style[styles[prop]] = url;
}
output.push(styles[prop]+':'+node.style[styles[prop]]+';');
output.push(styles[prop] + ':' + node.style[styles[prop]] + ';');
}
// re-add styles in case any are left
if(output.length) {
if (output.length) {
node.setAttribute('style', output.join(""));

@@ -393,0 +405,0 @@ } else {

@@ -6,4 +6,13 @@ {

"jshint": "node node_modules/jshint/bin/jshint src/purify.js || true",
"test": "npm run jshint;./node_modules/.bin/karma start test/karma.conf.js --single-run"
"minify": "scripts/minify.sh",
"amend-minified": "scripts/amend-minified.sh",
"test": "npm run jshint;./node_modules/.bin/karma start test/karma.conf.js --single-run",
"local-test": "npm run jshint;./node_modules/.bin/karma start test/karma.conf.js --browsers Chrome --single-run"
},
"pre-commit": [
"jshint",
"minify",
"local-test",
"amend-minified"
],
"devDependencies": {

@@ -19,6 +28,9 @@ "jshint": "^2.4.4",

"karma-json-fixtures-preprocessor": "0.0.5",
"karma-mocha-reporter": "^1.1.1",
"karma-qunit": "^0.1.5",
"karma-webpack": "^1.7.0",
"pre-commit": "^1.1.1",
"qunit-parameterize": "^0.4.0",
"qunitjs": "^1.14.0",
"uglify-js": "^2.4.24",
"webpack": "^1.12.1"

@@ -28,4 +40,4 @@ },

"description": "DOMPurify is a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG. It's written in JavaScript and works in all modern browsers (Safari, Opera (15+), Internet Explorer (10+), Firefox and Chrome - as well as almost anything else using Blink or WebKit). DOMPurify is written by security people who have vast background in web attacks and XSS. Fear not.",
"version": "0.6.7",
"main": "purify.js",
"version": "0.7.0",
"main": "src/purify.js",
"directories": {

@@ -32,0 +44,0 @@ "test": "test"

@@ -7,3 +7,3 @@ # DOMPurify [![Bower version](https://badge.fury.io/bo/dompurify.svg)](http://badge.fury.io/bo/dompurify) · [![npm version](https://badge.fury.io/js/dompurify.svg)](http://badge.fury.io/js/dompurify) · [![Build Status](https://travis-ci.org/cure53/DOMPurify.svg?branch=master)](https://travis-ci.org/cure53/DOMPurify)

It's written in JavaScript and works in all modern browsers (Safari, Opera (15+), Internet Explorer (10+), Spartan, Firefox and Chrome - as well as almost anything else using Blink or WebKit). It doesn't break on IE6 or other legacy browsers. It simply does nothing there.
It's written in JavaScript and works in all modern browsers (Safari, Opera (15+), Internet Explorer (10+), Spartan, Firefox and Chrome - as well as almost anything else using Blink or WebKit). It doesn't break on IE6 or other legacy browsers. It simply does nothing there. Our automated tests cover 8 different browsers right now.

@@ -16,3 +16,2 @@ 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)

## How do I use it?

@@ -22,6 +21,14 @@

### Using the unminified development version
```html
<script type="text/javascript" src="purify.js"></script>
<script type="text/javascript" src="src/purify.js"></script>
```
### Using the minified and tested production version (source-map available)
```html
<script type="text/javascript" src="dist/purify.min.js"></script>
```
Afterwards you can sanitize strings by executing the following code:

@@ -33,2 +40,4 @@

The resulting HTML can be written into a DOM element using `innerHTML` or the DOM using `document.write()`. That is fully up to you. But keep in mind, if you use the sanitized HTML with jQuery's very insecure `elm.html()` method, then the `SAFE_FOR_JQUERY` flag has to be set to make sure it's safe! Other than that, all is fine.
If you're using an [AMD](https://github.com/amdjs/amdjs-api/wiki/AMD) module loader like [Require.js](http://requirejs.org/), you can load this script asynchronously as well:

@@ -53,3 +62,2 @@

## Is there a demo?

@@ -72,3 +80,2 @@

DOMPurify.sanitize('<math><mi//xlink:href="data:x,<script>alert(4)</script>">'); // becomes <math></math>
DOMPurify.sanitize('<TABLE><tr><td>HELLO</tr></TABL>'); // becomes <table><tbody><tr><td>HELLO</td></tr></tbody></table>

@@ -161,8 +168,7 @@ DOMPurify.sanitize('<UL><li><A HREF=//google.com>click</UL>'); // becomes <ul><li><a href="//google.com">click</a></li></ul>

## Continuous Integration
## Unit tests
We are currently using Travis CI 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://travis-ci.org/cure53/DOMPurify
To run the test suite, you need [Node.js](http://nodejs.org/download/) first. Install the dependencies with `npm install`, then start the test server with `npm test`. You can run the tests in your browser from **http://localhost:8000/test/**.
## Security Mailing List

@@ -177,3 +183,3 @@

We recently implemented a Hook-API allowing developers to create their own DOMPurify plugins and customize its functionality without changing the core. Thus, we are looking forward for plugins and extensions - pull requests are welcome!
We recently implemented a Hook-API allowing developers to create their own DOMPurify plugins and customize its functionality without changing the core. Thus, we are looking forward for plugins and extensions - pull requests are welcome! Oh, and we will increase the amount of browsers and HTML-mappings in our automates tests to make sure nothing slips through.

@@ -180,0 +186,0 @@ ## Who contributed?

@@ -24,3 +24,3 @@ ;(function(factory) {

*/
DOMPurify.version = '0.6.7';
DOMPurify.version = '0.7.0';

@@ -53,2 +53,3 @@ if (!window || !window.document || window.document.nodeType !== 9) {

}
var implementation = document.implementation;
var createNodeIterator = document.createNodeIterator;

@@ -65,3 +66,4 @@ var getElementsByTagName = document.getElementsByTagName;

DOMPurify.isSupported =
typeof DOMParser !== 'undefined' && document.documentMode !== 9;
typeof implementation.createHTMLDocument !== 'undefined' &&
document.documentMode !== 9;

@@ -307,9 +309,25 @@ /* Add properties to a lookup table */

var _initDocument = function(dirty) {
/* Create a HTML document using DOMParser */
var doc = new DOMParser().parseFromString(dirty, "text/html");
var doc, body;
try {
doc = new DOMParser().parseFromString(dirty, "text/html");
} catch (e) {}
/* Some browsers throw, some browsers return null for the code above
DOMParser with text/html support is only in very recent browsers. */
if (!doc){
doc = implementation.createHTMLDocument('');
body = doc.body;
body.parentNode.removeChild(body.parentNode.firstElementChild);
body.outerHTML = dirty;
}
/* Work on whole document or just its body */
return getElementsByTagName.call(doc,
WHOLE_DOCUMENT ? 'html' : 'body')[0];
if (typeof doc.getElementsByTagName === 'function'){
return doc.getElementsByTagName(
WHOLE_DOCUMENT ? 'html' : 'body')[0];
} else {
return getElementsByTagName.call(doc,
WHOLE_DOCUMENT ? 'html' : 'body')[0];
}
};

@@ -429,8 +447,8 @@

var hookEvent = {
attrName: '',
attrValue: '',
keepAttr: true
},
l = attributes.length,
attr, name, value, lcName, idAttr;
attrName: '',
attrValue: '',
keepAttr: true
};
var l = attributes.length;
var attr, name, value, lcName, idAttr;

@@ -570,2 +588,6 @@ /* Go backwards over all attributes; safely remove bad ones */

DOMPurify.sanitize = function(dirty, cfg) {
if (!dirty) {
dirty = '';
}
/* Check we can run. Otherwise fall back or ignore */

@@ -572,0 +594,0 @@ if (!DOMPurify.isSupported) {

@@ -9,2 +9,3 @@ module.exports = function(config) {

'node_modules/qunit-parameterize/qunit-parameterize.js',
'test/config/setup.js',
'test/**/*.spec.js'

@@ -18,3 +19,3 @@ ],

reporters: ['progress'],
reporters: ['mocha'],

@@ -37,3 +38,4 @@ exclude: [],

'test',
'src'
'src',
'dist'
],

@@ -84,3 +86,3 @@ extensions: ['', '.js', '.json']

},
bs_yosemite_safari8: {
bs_yosemite_safari_8: {
base: 'BrowserStack',

@@ -93,3 +95,3 @@ device: null,

},
bs_win81_opera31: {
bs_win81_opera_31: {
base: 'BrowserStack',

@@ -101,2 +103,18 @@ device: null,

os_version: '8.1'
},
bs_win7_firefox_12: {
base: 'BrowserStack',
device: null,
os: 'Windows',
browser_version: '12.0',
browser: 'firefox',
os_version: '7'
},
bs_win81_chrome_22: {
base: 'BrowserStack',
device: null,
os: 'Windows',
browser_version: '22.0',
browser: 'chrome',
os_version: '8.1'
}

@@ -110,3 +128,6 @@ },

'bs_yosemite_firefox_40',
'bs_win81_opera31'
'bs_yosemite_safari_8',
'bs_win81_opera_31',
'bs_win7_firefox_12',
'bs_win81_chrome_22'
],

@@ -116,2 +137,3 @@

'karma-webpack',
'karma-mocha-reporter',
'karma-chrome-launcher',

@@ -118,0 +140,0 @@ 'karma-browserstack-launcher',

var
DOMPurify = require('purify'),
testSuite = require('test-suite'),
tests = require('fixtures/expect'),

@@ -8,218 +9,3 @@ xssTests = tests.filter( function( element ) {

window.alert = function() {
window.xssed = true;
};
QUnit.assert.contains = function( needle, haystack, message ) {
var result = haystack.indexOf(needle) > -1;
QUnit.push(result, needle, haystack, message);
};
QUnit.module( "DOMPurifyr", {
beforeEach: function() {
}
});
QUnit
.cases(tests)
.test( 'Sanitization test', function(params, assert) {
assert.contains( DOMPurify.sanitize( params.payload ), params.expected, 'Payload: ' + params.payload);
});
// Config-Flag Tests
QUnit.test( 'Config-Flag tests: KEEP_CONTENT + ALLOWED_TAGS / ALLOWED_ATTR', function(assert) {
// KEEP_CONTENT + ALLOWED_TAGS / ALLOWED_ATTR
assert.equal( DOMPurify.sanitize( '<iframe>Hello</iframe>', {KEEP_CONTENT: false} ), "");
assert.contains( DOMPurify.sanitize( '<a href="#">abc<b style="color:red">123</b><q class="cite">123</b></a>', {ALLOWED_TAGS: ['b', 'q'], ALLOWED_ATTR: ['style'], KEEP_CONTENT: true}),
["abc<b style=\"color:red\">123</b><q>123</q>", "abc<b style=\"color: red;\">123</b><q>123</q>"]
);
assert.equal( DOMPurify.sanitize( '<a href="#">abc<b style="color:red">123</b><q class="cite">123</b></a>', {ALLOWED_TAGS: ['b', 'q'], ALLOWED_ATTR: ['style'], KEEP_CONTENT: false}), "");
assert.equal( DOMPurify.sanitize( '<a href="#">abc</a>', {ALLOWED_TAGS: ['b', 'q'], KEEP_CONTENT: false}), "");
assert.equal( DOMPurify.sanitize( '<form><input name="parentNode"></form>', {ALLOWED_TAGS: ['input'], KEEP_CONTENT: true}), "<input>" );
});
QUnit.test( 'Config-Flag tests: ALLOW_DATA_ATTR', function(assert) {
// ALLOW_DATA_ATTR
assert.equal( DOMPurify.sanitize( '<a href="#" data-abc\"="foo">abc</a>', {ALLOW_DATA_ATTR: true}), "<a href=\"#\">abc</a>" );
assert.equal( DOMPurify.sanitize( '<a href="#" data-abc="foo">abc</a>', {ALLOW_DATA_ATTR: false}), "<a href=\"#\">abc</a>" );
assert.contains( DOMPurify.sanitize( '<a href="#" data-abc="foo">abc</a>', {ALLOW_DATA_ATTR: true}),
["<a data-abc=\"foo\" href=\"#\">abc</a>", "<a href=\"#\" data-abc=\"foo\">abc</a>"]
);
assert.contains( DOMPurify.sanitize( '<a href="#" data-abc-1-2-3="foo">abc</a>', {ALLOW_DATA_ATTR: true}),
["<a data-abc-1-2-3=\"foo\" href=\"#\">abc</a>", "<a href=\"#\" data-abc-1-2-3=\"foo\">abc</a>"]
);
assert.equal( DOMPurify.sanitize( '<a href="#" data-""="foo">abc</a>', {ALLOW_DATA_ATTR: true}), "<a href=\"#\">abc</a>" );
assert.contains( DOMPurify.sanitize( '<a href="#" data-äöü="foo">abc</a>', {ALLOW_DATA_ATTR: true}),
["<a href=\"#\" data-äöü=\"foo\">abc</a>", "<a data-äöü=\"foo\" href=\"#\">abc</a>"]
);
assert.contains( DOMPurify.sanitize( '<a href="#" data-\u00B7._="foo">abc</a>', {ALLOW_DATA_ATTR: true}),
["<a data-\u00B7._=\"foo\" href=\"#\">abc</a>", "<a href=\"#\">abc</a>"] // IE11 and Edge throw an InvalidCharacterError
);
assert.equal( DOMPurify.sanitize( '<a href="#" data-\u00B5="foo">abc</a>', {ALLOW_DATA_ATTR: true}), "<a href=\"#\">abc</a>" );
});
QUnit.test( 'Config-Flag tests: ADD_TAGS', function(assert) {
// ADD_TAGS
assert.equal( DOMPurify.sanitize( '<my-component>abc</my-component>', {ADD_TAGS: ['my-component']}), "<my-component>abc</my-component>" );
assert.equal( DOMPurify.sanitize( '<my-ĸompønent>abc</my-ĸompønent>', {ADD_TAGS: ['my-ĸompønent']}), "<my-ĸompønent>abc</my-ĸompønent>" );
});
QUnit.test( 'Config-Flag tests: ADD_TAGS + ADD_ATTR', function(assert) {
// ADD_TAGS + ADD_ATTR
assert.equal( DOMPurify.sanitize( '<my-component my-attr="foo">abc</my-component>', {ADD_TAGS: ['my-component']}), "<my-component>abc</my-component>" );
assert.equal( DOMPurify.sanitize( '<my-component my-attr="foo">abc</my-component>', {ADD_TAGS: ['my-component'], ADD_ATTR: ['my-attr']}), "<my-component my-attr=\"foo\">abc</my-component>" );
assert.equal( DOMPurify.sanitize( '<my-ĸompønent my-æŧŧr="foo">abc</my-ĸompønent>', {ADD_TAGS: ['my-ĸompønent']}), "<my-ĸompønent>abc</my-ĸompønent>" );
assert.equal( DOMPurify.sanitize( '<my-ĸompønent my-æŧŧr="foo">abc</my-ĸompønent>', {ADD_TAGS: ['my-ĸompønent'], ADD_ATTR: ['my-æŧŧr']}), "<my-ĸompønent my-æŧŧr=\"foo\">abc</my-ĸompønent>" );
});
QUnit.test( 'Config-Flag tests: SAFE_FOR_JQUERY', function(assert) {
//SAFE_FOR_JQUERY
assert.equal( DOMPurify.sanitize( '<a>123</a><option><style><img src=x onerror=alert(1)>', {SAFE_FOR_JQUERY: false}), "<a>123</a><option><style><img src=x onerror=alert(1)></style></option>" );
assert.equal( DOMPurify.sanitize( '<a>123</a><option><style><img src=x onerror=alert(1)>', {SAFE_FOR_JQUERY: true}), "<a>123</a><option><style>&lt;img src=x onerror=alert(1)></style></option>" );
assert.equal( DOMPurify.sanitize( '<option><style></option></select><b><img src=xx: onerror=alert(1)></style></option>', {SAFE_FOR_JQUERY: false}), "<option><style></option></select><b><img src=xx: onerror=alert(1)></style></option>" );
assert.equal( DOMPurify.sanitize( '<option><style></option></select><b><img src=xx: onerror=alert(1)></style></option>', {SAFE_FOR_JQUERY: true}), "<option><style>&lt;/option>&lt;/select>&lt;b>&lt;img src=xx: onerror=alert(1)></style></option>" );
assert.equal( DOMPurify.sanitize( '<option><iframe></select><b><script>alert(1)<\/script>', {SAFE_FOR_JQUERY: false, KEEP_CONTENT: false}), "<option></option>" );
assert.equal( DOMPurify.sanitize( '<option><iframe></select><b><script>alert(1)<\/script>', {SAFE_FOR_JQUERY: true, KEEP_CONTENT: false}), "<option></option>" );
assert.equal( DOMPurify.sanitize( '<b><style><style/><img src=xx: onerror=alert(1)>', {SAFE_FOR_JQUERY: false}), "<b><style><style/><img src=xx: onerror=alert(1)></style></b>" );
assert.equal( DOMPurify.sanitize( '<b><style><style/><img src=xx: onerror=alert(1)>', {SAFE_FOR_JQUERY: true}), "<b><style>&lt;style/>&lt;img src=xx: onerror=alert(1)></style></b>" );
});
QUnit.test( 'Config-Flag tests: SANITIZE_DOM', function(assert) {
// SANITIZE_DOM
assert.equal( DOMPurify.sanitize( '<form name="window">', {SANITIZE_DOM: true}), "<form></form>" );
assert.equal( DOMPurify.sanitize( '<img src="x" name="implementation">', {SANITIZE_DOM: true}), '<img src="x">' );
assert.equal( DOMPurify.sanitize( '<img src="x" name="createNodeIterator">', {SANITIZE_DOM: true}), '<img src="x">' );
assert.equal( DOMPurify.sanitize( '<img src="x" name="getElementById">', {SANITIZE_DOM: false}), "<img name=\"getElementById\" src=\"x\">" );
assert.equal( DOMPurify.sanitize( '<img src="x" name="getElementById">', {SANITIZE_DOM: true}), "<img src=\"x\">" );
assert.equal( DOMPurify.sanitize( '<a href="x" id="location">click</a>', {SANITIZE_DOM: true}), "<a href=\"x\">click</a>" );
assert.contains( DOMPurify.sanitize( '<form><input name="attributes"></form>', {ADD_TAGS: ['form'], SANITIZE_DOM: false}),
["", "<form><input name=\"attributes\"></form>"]
);
assert.contains( DOMPurify.sanitize( '<form><input name="attributes"></form>', {ADD_TAGS: ['form'], SANITIZE_DOM: true}),
["", "<form><input name=\"attributes\"></form>", "<form><input></form>"]
);
});
QUnit.test( 'Config-Flag tests: WHOLE_DOCUMENT', function(assert) {
//WHOLE_DOCUMENT
assert.equal( DOMPurify.sanitize( '123', {WHOLE_DOCUMENT: false}), "123" );
assert.equal( DOMPurify.sanitize( '123', {WHOLE_DOCUMENT: true}), "<html><head></head><body>123</body></html>" );
assert.equal( DOMPurify.sanitize( '<style>*{color:red}</style>', {WHOLE_DOCUMENT: false}), "" );
assert.equal( DOMPurify.sanitize( '<style>*{color:red}</style>', {WHOLE_DOCUMENT: true}), "<html><head><style>*{color:red}</style></head><body></body></html>" );
assert.equal( DOMPurify.sanitize( '123<style>*{color:red}</style>', {WHOLE_DOCUMENT: false}), "123<style>*{color:red}</style>" );
assert.equal( DOMPurify.sanitize( '123<style>*{color:red}</style>', {WHOLE_DOCUMENT: true}), "<html><head></head><body>123<style>*{color:red}</style></body></html>" );
});
QUnit.test( 'Config-Flag tests: RETURN_DOM', function(assert) {
//RETURN_DOM
assert.equal( DOMPurify.sanitize( '<a>123<b>456</b></a>', {RETURN_DOM: true}).outerHTML, "<body><a>123<b>456</b></a></body>" );
assert.equal( DOMPurify.sanitize( '<a>123<b>456<script>alert(1)<\/script></b></a>', {RETURN_DOM: true}).outerHTML, "<body><a>123<b>456</b></a></body>" );
assert.equal( DOMPurify.sanitize( '<a>123<b>456</b></a>', {RETURN_DOM: true, WHOLE_DOCUMENT: true}).outerHTML, "<html><head></head><body><a>123<b>456</b></a></body></html>" );
assert.equal( DOMPurify.sanitize( '<a>123<b>456<script>alert(1)<\/script></b></a>', {RETURN_DOM: true, WHOLE_DOCUMENT: true}).outerHTML, "<html><head></head><body><a>123<b>456</b></a></body></html>" );
assert.equal( DOMPurify.sanitize( '123', {RETURN_DOM: true}).outerHTML, "<body>123</body>" );
});
QUnit.test( 'Config-Flag tests: RETURN_DOM_IMPORT', function(assert) {
//RETURN_DOM_IMPORT
assert.notEqual( DOMPurify.sanitize( '123', {RETURN_DOM : true }).ownerDocument, document );
assert.notEqual( DOMPurify.sanitize( '123', {RETURN_DOM : true, RETURN_DOM_IMPORT: false}).ownerDocument, document );
assert.equal ( DOMPurify.sanitize( '123', {RETURN_DOM : true, RETURN_DOM_IMPORT: true }).ownerDocument, document );
assert.notEqual( DOMPurify.sanitize( '123', {RETURN_DOM_FRAGMENT: true }).ownerDocument, document );
assert.notEqual( DOMPurify.sanitize( '123', {RETURN_DOM_FRAGMENT: true, RETURN_DOM_IMPORT: false}).ownerDocument, document );
assert.equal ( DOMPurify.sanitize( '123', {RETURN_DOM_FRAGMENT: true, RETURN_DOM_IMPORT: true }).ownerDocument, document );
});
QUnit.test( 'Config-Flag tests: RETURN_DOM_FRAGMENT', function(assert) {
//RETURN_DOM_FRAGMENT
// attempt clobbering
var fragment = DOMPurify.sanitize( 'foo<img id="createDocumentFragment">', {RETURN_DOM_FRAGMENT: true});
assert.equal(fragment.nodeType, 11);
assert.notEqual(fragment.ownerDocument, document);
assert.equal(fragment.firstChild && fragment.firstChild.nodeValue, 'foo');
// again, but without SANITIZE_DOM
fragment = DOMPurify.sanitize( 'foo<img id="createDocumentFragment">', {RETURN_DOM_FRAGMENT: true, SANITIZE_DOM: false});
assert.equal(fragment.nodeType, 11);
assert.notEqual(fragment.ownerDocument, document);
assert.equal(fragment.firstChild && fragment.firstChild.nodeValue, 'foo');
});
QUnit.test( 'Config-Flag tests: FORBID_TAGS', function(assert) {
//FORBID_TAGS
assert.equal( DOMPurify.sanitize( '<a>123<b>456</b></a>', {FORBID_TAGS: ['b']}), "<a>123456</a>" );
assert.equal( DOMPurify.sanitize( '<a>123<b>456<script>alert(1)<\/script></b></a>789', {FORBID_TAGS: ['a', 'b']}), "123456789" );
assert.equal( DOMPurify.sanitize( '<a>123<b>456</b></a>', {FORBID_TAGS: ['c']}), "<a>123<b>456</b></a>" );
assert.equal( DOMPurify.sanitize( '<a>123<b>456<script>alert(1)<\/script></b></a>789', {FORBID_TAGS: ['script', 'b']}), "<a>123456</a>789" );
assert.equal( DOMPurify.sanitize( '<a>123<b>456</b></a>', {ADD_TAGS: ['b'], FORBID_TAGS: ['b']}), "<a>123456</a>" );
});
QUnit.test( 'Config-Flag tests: FORBID_ATTR', function(assert) {
//FORBID_ATTR
assert.equal( DOMPurify.sanitize( '<a x="1">123<b>456</b></a>', {FORBID_ATTR: ['x']}), "<a>123<b>456</b></a>" );
assert.equal( DOMPurify.sanitize( '<a class="0" x="1">123<b y="1">456<script>alert(1)<\/script></b></a>789', {FORBID_ATTR: ['x', 'y']}), "<a class=\"0\">123<b>456</b></a>789" );
assert.equal( DOMPurify.sanitize( '<a y="1">123<b y="1" y="2">456</b></a>', {FORBID_ATTR: ['y']}), "<a>123<b>456</b></a>" );
assert.equal( DOMPurify.sanitize( '<a>123<b x="1">456<script y="1">alert(1)<\/script></b></a>789', {FORBID_ATTR: ['x', 'y']}), "<a>123<b>456</b></a>789" );
});
// XSS tests: Native DOM methods (alert() should not be called)
QUnit
.cases(xssTests)
.asyncTest('XSS test: native', function(params, assert) {
document.getElementById( 'qunit-fixture' ).innerHTML = DOMPurify.sanitize( params.payload );
setTimeout(function() {
QUnit.start();
assert.notEqual( window.xssed, true, 'alert() was called' );
// Teardown
document.getElementById( 'qunit-fixture' ).innerHTML = '';
window.xssed = false;
}, 100);
});
// XSS tests: jQuery (alert() should not be called)
QUnit
.cases(xssTests)
.asyncTest('XSS test: jQuery', function(params, assert) {
jQuery( '#qunit-fixture' ).html( DOMPurify.sanitize( params.payload, {SAFE_FOR_JQUERY: true} ) );
setTimeout(function() {
QUnit.start();
assert.notEqual( window.xssed, true, 'alert() was called' );
// Teardown
jQuery( '#qunit-fixture' ).empty();
window.xssed = false;
}, 100);
});
// Check for isSupported property
QUnit.test( 'DOMPurify property tests', function(assert) {
assert.equal( typeof DOMPurify.isSupported, 'boolean' );
});
// Test with a custom window object
QUnit.test( 'DOMPurify custom window tests', function(assert) {
assert.strictEqual(typeof DOMPurify(null).version, 'string');
assert.strictEqual(DOMPurify(null).isSupported, false);
assert.strictEqual(DOMPurify(null).sanitize, undefined);
assert.strictEqual(typeof DOMPurify({}).version, 'string');
assert.strictEqual(DOMPurify({}).isSupported, false);
assert.strictEqual(DOMPurify({}).sanitize, undefined);
assert.strictEqual(typeof DOMPurify({document: 'not really a document'}).version, 'string');
assert.strictEqual(DOMPurify({document: 'not really a document'}).isSupported, false);
assert.strictEqual(DOMPurify({document: 'not really a document'}).sanitize, undefined);
assert.strictEqual(typeof DOMPurify(window).version, 'string');
assert.strictEqual(typeof DOMPurify(window).sanitize, 'function');
});
// Test to prevent security issues with pre-clobbered DOM
QUnit.test( 'sanitize() should not throw if the original document is clobbered _after_ DOMPurify has been instantiated', function(assert) {
var evilNode = document.createElement('div');
evilNode.innerHTML = '<img id="implementation"><img id="createNodeIterator"><img id="importNode"><img id="createElement">';
document.body.appendChild(evilNode);
try {
// tests implementation and createNodeIterator
var resultPlain = DOMPurify.sanitize('123');
// tests importNode
var resultImport = DOMPurify.sanitize( '123', {RETURN_DOM : true, RETURN_DOM_IMPORT: true });
// tests createElement
var resultBody = DOMPurify.sanitize( '123<img id="body">');
} finally {
// clean up before doing the actual assertions, otherwise qunit/jquery/etc might blow up
document.body.removeChild(evilNode);
}
assert.equal( resultPlain, '123' );
assert.equal( resultImport.ownerDocument, document );
assert.equal( resultBody, '123<img>' );
} );
// Test to check against a hang in MSIE (#89)
QUnit.test( 'sanitize() should not hang on MSIE when hook changes textContent', function(assert) {
DOMPurify.addHook('afterSanitizeElements', function(node) {
if (node.nodeType && node.nodeType === document.TEXT_NODE) {
node.textContent = 'foo';
}
return node;
});
var dirty = '<div><p>This is a beatufiul text</p><p>This is too</p></div>';
var modified = '<div><p>foo</p><p>foo</p></div>';
assert.equal(modified, DOMPurify.sanitize(dirty));
DOMPurify.removeHooks('afterSanitizeElements')
} );
QUnit.module('DOMPurify src');
testSuite(DOMPurify, tests, xssTests);

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc