From b5b41083b094ca0415ef63b544542c7143ff168d Mon Sep 17 00:00:00 2001 From: Raphael Jamet Date: Fri, 27 May 2016 14:13:09 +0200 Subject: [PATCH] fix($compile): turn link[href] into a RESOURCE_URL context. For now, there's no security in there, so a dynamic href has no protections against evil stylesheets. It shouldn't be a common pattern anyways, but an user-controlled import or stylesheet (and serviceworkers seem to be in the works too) can run script in your origin, which warrants the RESOURCE_URL context. --- src/ng/compile.js | 2 ++ test/ng/compileSpec.js | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/ng/compile.js b/src/ng/compile.js index 2780fd76435d..1f443d1dba37 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -2953,6 +2953,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { // maction[xlink:href] can source SVG. It's not limited to . if (attrNormalizedName === "xlinkHref" || (tag === "form" && attrNormalizedName === "action") || + // links can be stylesheets or imports, which can run script in the current origin + (tag === "link" && attrNormalizedName === "href") || (tag !== "img" && (attrNormalizedName === "src" || attrNormalizedName === "ngSrc"))) { return $sce.RESOURCE_URL; diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index b1dd097e99a8..c2f739df4b57 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -10002,6 +10002,7 @@ describe('$compile', function() { "loading resource from url not allowed by $sceDelegate policy. URL: javascript:doTrustedStuff()"); })); + it('should pass through $sce.trustAs() values in action attribute', inject(function($compile, $rootScope, $sce) { /* jshint scripturl:true */ element = $compile('
')($rootScope); @@ -10012,6 +10013,36 @@ describe('$compile', function() { })); }); + describe('link[href]', function() { + it('should reject invalid RESOURCE_URLs', inject(function($compile, $rootScope) { + element = $compile('')($rootScope); + $rootScope.testUrl = "https://evil.example.org/css.css"; + expect(function() { $rootScope.$apply(); }).toThrowMinErr( + "$interpolate", "interr", "Can't interpolate: {{testUrl}}\nError: [$sce:insecurl] Blocked " + + "loading resource from url not allowed by $sceDelegate policy. URL: " + + "https://evil.example.org/css.css"); + })); + + it('should accept valid RESOURCE_URLs', inject(function($compile, $rootScope, $sce) { + element = $compile('')($rootScope); + + $rootScope.testUrl = "./css1.css"; + $rootScope.$apply(); + expect(element.attr('href')).toContain('css1.css'); + + $rootScope.testUrl = $sce.trustAsResourceUrl('https://elsewhere.example.org/css2.css'); + $rootScope.$apply(); + expect(element.attr('href')).toContain('https://elsewhere.example.org/css2.css'); + })); + + it('should accept valid constants', inject(function($compile, $rootScope) { + element = $compile('')($rootScope); + + $rootScope.$apply(); + expect(element.attr('href')).toContain('https://elsewhere.example.org/css2.css'); + })); + }); + if (!msie || msie >= 11) { describe('iframe[srcdoc]', function() { it('should NOT set iframe contents for untrusted values', inject(function($compile, $rootScope, $sce) {