diff --git a/src/ng/compile.js b/src/ng/compile.js index 028901f0644d..eff02b1a4201 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -1671,9 +1671,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { nodeName = nodeName_(this.$$element); if ((nodeName === 'a' && (key === 'href' || key === 'xlinkHref')) || - (nodeName === 'img' && key === 'src')) { + (nodeName === 'img' && key === 'src') || + (nodeName === 'image' && key === 'xlinkHref')) { // sanitize a[href] and img[src] values - this[key] = value = $$sanitizeUri(value, key === 'src'); + this[key] = value = + $$sanitizeUri(value, nodeName === 'img' || nodeName === 'image'); } else if (nodeName === 'img' && key === 'srcset' && isDefined(value)) { // sanitize img[srcset] values var result = ''; @@ -3254,8 +3256,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { if (['img', 'video', 'audio', 'source', 'track'].indexOf(tag) === -1) { return $sce.RESOURCE_URL; } - // maction[xlink:href] can source SVG. It's not limited to . - } else if (attrNormalizedName === 'xlinkHref' || + } else if ( + // Some xlink:href are okay, most aren't + (attrNormalizedName === 'xlinkHref' && (tag !== 'image' && tag !== 'a')) || + // Formaction (tag === 'form' && attrNormalizedName === 'action') || // If relative URLs can go where they are not expected to, then // all sorts of trust issues can arise. diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index 59c685753f99..791c21ee062c 100644 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -11122,23 +11122,47 @@ describe('$compile', function() { }); it('should use $$sanitizeUri when working with svg and xlink:href', function() { + var $$sanitizeUri = jasmine.createSpy('$$sanitizeUri'); + module(function($provide) { + $provide.value('$$sanitizeUri', $$sanitizeUri); + }); + inject(function($compile, $rootScope) { + var elementA = $compile('')($rootScope); + var elementImage = $compile('')($rootScope); + + //both of these fail the RESOURCE_URL test, that shouldn't be run + $rootScope.testUrl = 'https://bad.example.org'; + $$sanitizeUri.and.returnValue('https://clean.example.org'); + + $rootScope.$apply(); + expect(elementA.find('a').attr('xlink:href')).toBe('https://clean.example.org'); + expect(elementImage.find('image').attr('xlink:href')).toBe('https://clean.example.org'); + // is navigational, so the second argument should be false to reach the aHref whitelist + expect($$sanitizeUri).toHaveBeenCalledWith($rootScope.testUrl + 'aTag' , false); + // is media inclusion, it should use the imgSrc whitelist + expect($$sanitizeUri).toHaveBeenCalledWith($rootScope.testUrl + 'imageTag', true); + }); + }); + + it('should use $$sanitizeUri when working with svg and xlink:href through ng-href', function() { var $$sanitizeUri = jasmine.createSpy('$$sanitizeUri'); module(function($provide) { $provide.value('$$sanitizeUri', $$sanitizeUri); }); inject(function($compile, $rootScope) { element = $compile('')($rootScope); - $rootScope.testUrl = 'evilUrl'; + //both of these fail the RESOURCE_URL test, that shouldn't be run + $rootScope.testUrl = 'https://bad.example.org'; + $$sanitizeUri.and.returnValue('https://clean.example.org'); - $$sanitizeUri.and.returnValue('someSanitizedUrl'); $rootScope.$apply(); - expect(element.find('a').prop('href').baseVal).toBe('someSanitizedUrl'); + expect(element.find('a').prop('href').baseVal).toBe('https://clean.example.org'); expect($$sanitizeUri).toHaveBeenCalledWith($rootScope.testUrl, false); }); }); - it('should use $$sanitizeUri when working with svg and xlink:href', function() { + it('should use $$sanitizeUri when working with svg and xlink:href through ng-href', function() { var $$sanitizeUri = jasmine.createSpy('$$sanitizeUri'); module(function($provide) { $provide.value('$$sanitizeUri', $$sanitizeUri); @@ -11153,6 +11177,17 @@ describe('$compile', function() { expect($$sanitizeUri).toHaveBeenCalledWith($rootScope.testUrl, false); }); }); + + it('should have a RESOURCE_URL context for xlink:href by default', function() { + inject(function($compile, $rootScope) { + element = $compile('')($rootScope); + $rootScope.testUrl = 'https://bad.example.org'; + + expect(function() { + $rootScope.$apply(); + }).toThrowError(/\$sce:insecurl/); + }); + }); }); describe('interpolation on HTML DOM event handler attributes onclick, onXYZ, formaction', function() {