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

Commit 465d173

Browse files
Rob--Wpetebacondarwin
authored andcommitted
feat(security): do not bootstrap from unknown schemes with a different origin
1 parent f1db7d7 commit 465d173

File tree

2 files changed

+40
-4
lines changed

2 files changed

+40
-4
lines changed

src/Angular.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -1485,12 +1485,14 @@ function allowAutoBootstrap(document) {
14851485
var src = document.currentScript.getAttribute('src');
14861486
var link = document.createElement('a');
14871487
link.href = src;
1488-
var scriptProtocol = link.protocol;
1489-
var docLoadProtocol = document.location.protocol;
1490-
if (docLoadProtocol === scriptProtocol) {
1488+
if (document.location.origin === link.origin) {
1489+
// Same-origin resources are always allowed, even for non-whitelisted schemes.
14911490
return true;
14921491
}
1493-
switch (scriptProtocol) {
1492+
// Disabled bootstrapping unless angular.js was loaded from a known scheme used on the web.
1493+
// This is to prevent angular.js bundled with browser extensions from being used to bypass the
1494+
// content security policy in web pages and other browser extensions.
1495+
switch (link.protocol) {
14941496
case 'http:':
14951497
case 'https:':
14961498
case 'ftp:':

test/AngularSpec.js

+34
Original file line numberDiff line numberDiff line change
@@ -1683,7 +1683,41 @@ describe('angular', function() {
16831683
dealoc(appElement);
16841684
});
16851685

1686+
it('should bootstrap from an extension into an extension document for same-origin documents only', function() {
1687+
if (msie) return; // IE does not support document.currentScript (nor extensions with protocol), so skip test.
1688+
1689+
// Extension URLs are browser-specific, so we must choose a scheme that is supported by the browser to make
1690+
// sure that the URL is properly parsed.
1691+
var extensionScheme;
1692+
var userAgent = window.navigator.userAgent;
1693+
if (/Firefox\//.test(userAgent)) {
1694+
extensionScheme = 'moz-extension';
1695+
} else if (/Edge\//.test(userAgent)) {
1696+
extensionScheme = 'ms-browser-extension';
1697+
} else if (/Chrome\//.test(userAgent)) {
1698+
extensionScheme = 'chrome-extension';
1699+
} else if (/Safari\//.test(userAgent)) {
1700+
extensionScheme = 'safari-extension';
1701+
} else {
1702+
extensionScheme = 'browserext'; // Upcoming standard scheme.
1703+
}
1704+
1705+
var src = extensionScheme + '://something';
1706+
// Fake a minimal document object (the actual document.currentScript is readonly).
1707+
var fakeDoc = {
1708+
currentScript: { getAttribute: function() { return src; } },
1709+
location: {protocol: extensionScheme + ':', origin: extensionScheme + '://something'},
1710+
createElement: document.createElement.bind(document)
1711+
};
1712+
expect(allowAutoBootstrap(fakeDoc)).toBe(true);
1713+
1714+
src = extensionScheme + '://something-else';
1715+
expect(allowAutoBootstrap(fakeDoc)).toBe(false);
1716+
});
1717+
16861718
it('should not bootstrap from an extension into a non-extension document', function() {
1719+
if (msie) return; // IE does not support document.currentScript (nor extensions with protocol), so skip test.
1720+
16871721
var src = 'resource://something';
16881722
// Fake a minimal document object (the actual document.currentScript is readonly).
16891723
var fakeDoc = {

0 commit comments

Comments
 (0)