From 667db466f959f8bbca1451d0f1c1a3db25d46a6c Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Tue, 31 Oct 2017 21:41:28 +0000 Subject: [PATCH] fix(sanitizeUri): sanitize URIs that contain IDEOGRAPHIC SPACE chars Browsers mutate attributes values such as ` javascript:alert(1)` when they are written to the DOM via `innerHTML` in various vendor specific ways. In Chrome (<62), this mutation removed the preceding "whitespace" resulting in a value that could end up being executed as JavaScript. Here is an example of what could happen: https://plnkr.co/edit/Y6EsbsuDgd18YTn1oARu?p=preview If you run that in Chrome 61 you will get a dialog box pop up. There is background here: http://www.nds.rub.de/media/emma/veroeffentlichungen/2013/12/10/mXSS-CCS13.pdf The sanitizer has a bit of code that triggers this mutation on an inert piece of DOM, before we try to sanitize it: https://github.com/angular/angular.js/blob/817ac567/src/ngSanitize/sanitize.js#L406-L417 Chrome 62 does not appear to mutate this particular string any more, instead it just leaves the "whitespace" in place. This probably means that Chrome 62 is no longer vulnerable to this specific attack vector; but there may be other mutating strings that we haven't found, which are vulnerable. Since we are leaving the mXSS check in place, the sanitizer should still be immune to any strings that try to utilise this attack vector. This commit uses `trim()` to remove the IDEOGRAPHIC SPACE "whitespace" before sanitizing, which allows us to expose this mXSS test to all browsers rather than just Chrome. Closes #16288 --- src/ng/sanitizeUri.js | 2 +- test/ngSanitize/sanitizeSpec.js | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/ng/sanitizeUri.js b/src/ng/sanitizeUri.js index a5302994415d..f7dc60bf3c41 100644 --- a/src/ng/sanitizeUri.js +++ b/src/ng/sanitizeUri.js @@ -62,7 +62,7 @@ function $$SanitizeUriProvider() { return function sanitizeUri(uri, isImage) { var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist; var normalizedVal; - normalizedVal = urlResolve(uri).href; + normalizedVal = urlResolve(uri && uri.trim()).href; if (normalizedVal !== '' && !normalizedVal.match(regex)) { return 'unsafe:' + normalizedVal; } diff --git a/test/ngSanitize/sanitizeSpec.js b/test/ngSanitize/sanitizeSpec.js index c3206948e990..2bab68093181 100644 --- a/test/ngSanitize/sanitizeSpec.js +++ b/test/ngSanitize/sanitizeSpec.js @@ -237,11 +237,9 @@ describe('HTML', function() { .toEqual(''); }); - if (isChrome) { - it('should prevent mXSS attacks', function() { - expectHTML('CLICKME').toBe('CLICKME'); - }); - } + it('should prevent mXSS attacks', function() { + expectHTML('CLICKME').toBe('CLICKME'); + }); it('should strip html comments', function() { expectHTML('

text1text2

')