From 0421cb4200e672818ed10996e92311404c150c3a Mon Sep 17 00:00:00 2001 From: Chirayu Krishnappa Date: Tue, 12 Nov 2013 15:32:52 -0800 Subject: [PATCH] fix($compile): secure form[action] & iframe[srcdoc] Require bindings to form[action] to be $sce.RESOURCE_URL and bindings to iframe[srcdoc] to be $sce.HTML Closes #4927 Closes #4933 --- src/ng/compile.js | 9 ++++-- test/ng/compileSpec.js | 70 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/ng/compile.js b/src/ng/compile.js index d977f173bf7d..4eb12019adfe 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -1780,10 +1780,15 @@ function $CompileProvider($provide) { function getTrustedContext(node, attrNormalizedName) { + if (attrNormalizedName == "srcdoc") { + return $sce.HTML; + } + var tag = nodeName_(node); // maction[xlink:href] can source SVG. It's not limited to . if (attrNormalizedName == "xlinkHref" || - (nodeName_(node) != "IMG" && (attrNormalizedName == "src" || - attrNormalizedName == "ngSrc"))) { + (tag == "FORM" && attrNormalizedName == "action") || + (tag != "IMG" && (attrNormalizedName == "src" || + attrNormalizedName == "ngSrc"))) { return $sce.RESOURCE_URL; } } diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index 5b6e1ada83c0..99be8afc9f16 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -4232,6 +4232,76 @@ describe('$compile', function() { })); }); + describe('form[action]', function() { + it('should pass through action attribute for the same domain', inject(function($compile, $rootScope, $sce) { + element = $compile('
')($rootScope); + $rootScope.testUrl = "different_page"; + $rootScope.$apply(); + expect(element.attr('action')).toEqual('different_page'); + })); + + it('should clear out action attribute for a different domain', inject(function($compile, $rootScope, $sce) { + element = $compile('
')($rootScope); + $rootScope.testUrl = "http://a.different.domain.example.com"; + 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: " + + "http://a.different.domain.example.com"); + })); + + it('should clear out JS action attribute', inject(function($compile, $rootScope, $sce) { + element = $compile('
')($rootScope); + $rootScope.testUrl = "javascript:alert(1);"; + 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: " + + "javascript:alert(1);"); + })); + + it('should clear out non-resource_url action attribute', inject(function($compile, $rootScope, $sce) { + element = $compile('
')($rootScope); + $rootScope.testUrl = $sce.trustAsUrl("javascript:doTrustedStuff()"); + expect($rootScope.$apply).toThrowMinErr( + "$interpolate", "interr", "Can't interpolate: {{testUrl}}\nError: [$sce:insecurl] Blocked " + + "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) { + element = $compile('
')($rootScope); + $rootScope.testUrl = $sce.trustAsResourceUrl("javascript:doTrustedStuff()"); + $rootScope.$apply(); + + expect(element.attr('action')).toEqual('javascript:doTrustedStuff()'); + })); + }); + + if (!msie || msie >= 11) { + describe('iframe[srcdoc]', function() { + it('should NOT set iframe contents for untrusted values', inject(function($compile, $rootScope, $sce) { + element = $compile('')($rootScope); + $rootScope.html = '
hello
'; + expect(function() { $rootScope.$digest(); }).toThrowMinErr('$interpolate', 'interr', new RegExp( + /Can't interpolate: {{html}}\n/.source + + /[^[]*\[\$sce:unsafe\] Attempting to use an unsafe value in a safe context./.source)); + })); + + it('should NOT set html for wrongly typed values', inject(function($rootScope, $compile, $sce) { + element = $compile('')($rootScope); + $rootScope.html = $sce.trustAsCss('
hello
'); + expect(function() { $rootScope.$digest(); }).toThrowMinErr('$interpolate', 'interr', new RegExp( + /Can't interpolate: {{html}}\n/.source + + /[^[]*\[\$sce:unsafe\] Attempting to use an unsafe value in a safe context./.source)); + })); + + it('should set html for trusted values', inject(function($rootScope, $compile, $sce) { + element = $compile('')($rootScope); + $rootScope.html = $sce.trustAsHtml('
hello
'); + $rootScope.$digest(); + expect(angular.lowercase(element[0].srcdoc)).toEqual('
hello
'); + })); + }); + } + describe('ngAttr* attribute binding', function() { it('should bind after digest but not before', inject(function($compile, $rootScope) {