Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 0821355

Browse files
committed
fixup! fix($sanitize): prevent clobbered elements from freezing the browser
1 parent 9fe25ef commit 0821355

File tree

2 files changed

+28
-14
lines changed

2 files changed

+28
-14
lines changed

src/ngSanitize/sanitize.js

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ var forEach;
1818
var isDefined;
1919
var lowercase;
2020
var noop;
21+
var nodeContains;
2122
var htmlParser;
2223
var htmlSanitizeWriter;
2324

@@ -218,6 +219,11 @@ function $SanitizeProvider() {
218219
htmlParser = htmlParserImpl;
219220
htmlSanitizeWriter = htmlSanitizeWriterImpl;
220221

222+
nodeContains = window.Node.prototype.contains || /** @this */ function(arg) {
223+
// eslint-disable-next-line no-bitwise
224+
return !!(this.compareDocumentPosition(arg) & 16);
225+
};
226+
221227
// Regular Expressions for parsing tags and attributes
222228
var SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
223229
// Match everything outside of normal chars and " (quote character)
@@ -381,12 +387,12 @@ function $SanitizeProvider() {
381387
if (node.nodeType === 1) {
382388
handler.end(node.nodeName.toLowerCase());
383389
}
384-
nextNode = getNextSibling(node);
390+
nextNode = getNonDescendant('nextSibling', node);
385391
if (!nextNode) {
386392
while (nextNode == null) {
387-
node = node.parentNode;
393+
node = getNonDescendant('parentNode', node);
388394
if (node === inertBodyElement) break;
389-
nextNode = getNextSibling(node);
395+
nextNode = getNonDescendant('nextSibling', node);
390396
if (node.nodeType === 1) {
391397
handler.end(node.nodeName.toLowerCase());
392398
}
@@ -518,17 +524,17 @@ function $SanitizeProvider() {
518524
stripCustomNsAttrs(nextNode);
519525
}
520526

521-
node = getNextSibling(node);
527+
node = getNonDescendant('nextSibling', node);
522528
}
523529
}
524530

525-
function getNextSibling(node) {
526-
// An element is clobbered if its `nextSibling` property points to one of its children
527-
var nextNode = node.nextSibling;
528-
if (nextNode && nextNode.parentNode === node) {
531+
function getNonDescendant(propName, node) {
532+
// An element is clobbered if its `propName` property points to one of its descendants
533+
var nextNode = node[propName];
534+
if (nodeContains.call(node, nextNode)) {
529535
throw $sanitizeMinErr('elclob', 'Failed to sanitize html because the element is clobbered: {0}', node.outerHTML || node.outerText);
530536
}
531-
return node.nextSibling;
537+
return nextNode;
532538
}
533539
}
534540

test/ngSanitize/sanitizeSpec.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,6 @@ describe('HTML', function() {
2020
describe('htmlParser', function() {
2121
/* global htmlParser */
2222

23-
beforeEach(inject(function($sanitize) {
24-
// We actually need to inject $sanitize to set up the htmlParser object
25-
}));
26-
2723
var handler, start, text, comment;
2824
beforeEach(function() {
2925
text = '';
@@ -253,7 +249,19 @@ describe('HTML', function() {
253249
it('should remove clobbered elements', function() {
254250
inject(function($sanitize) {
255251
expect(function() {
256-
$sanitize('<form><input name=nextSibling></form>');
252+
$sanitize('<form><input name="parentNode" /></form>');
253+
}).toThrowMinErr('$sanitize', 'elclob');
254+
255+
expect(function() {
256+
$sanitize('<form><div><div><input name="parentNode" /></div></div></form>');
257+
}).toThrowMinErr('$sanitize', 'elclob');
258+
259+
expect(function() {
260+
$sanitize('<form><input name="nextSibling" /></form>');
261+
}).toThrowMinErr('$sanitize', 'elclob');
262+
263+
expect(function() {
264+
$sanitize('<form><div><div><input name="nextSibling" /></div></div></form>');
257265
}).toThrowMinErr('$sanitize', 'elclob');
258266
});
259267
});

0 commit comments

Comments
 (0)