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

Commit 48fa3aa

Browse files
thejhIgorMinar
authored andcommitted
fix($parse): forbid __{define,lookup}{Getter,Setter}__ properties
It was possible to use `{}.__defineGetter__.call(null, 'alert', (0).valueOf.bind(0))` to set `window.alert` to a false-ish value, thereby breaking the `isWindow` check, which might lead to arbitrary code execution in browsers that let you obtain the window object using Array methods. Prevent that by blacklisting the nasty __{define,lookup}{Getter,Setter}__ properties. BREAKING CHANGE: This prevents the use of __{define,lookup}{Getter,Setter}__ inside angular expressions. If you really need them for some reason, please wrap/bind them to make them less dangerous, then make them available through the scope object.
1 parent 528be29 commit 48fa3aa

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

src/ng/parse.js

+10
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ function ensureSafeMemberName(name, fullExpression) {
3636
throw $parseMinErr('isecfld',
3737
'Referencing "constructor" field in Angular expressions is disallowed! Expression: {0}',
3838
fullExpression);
39+
} else if (name === "__defineGetter__" || name === "__defineSetter__"
40+
|| name === "__lookupGetter__" || name === "__lookupSetter__") {
41+
throw $parseMinErr('isecgetset',
42+
'Defining and looking up getters and setters in Angular expressions is disallowed! '
43+
+'Expression: {0}', fullExpression);
3944
}
4045
return name;
4146
}
@@ -62,6 +67,11 @@ function ensureSafeObject(obj, fullExpression) {
6267
throw $parseMinErr('isecobj',
6368
'Referencing Object in Angular expressions is disallowed! Expression: {0}',
6469
fullExpression);
70+
} else if (obj === ({}).__defineGetter__ || obj === ({}).__defineSetter__
71+
|| obj === ({}).__lookupGetter__ || obj === ({}).__lookupSetter__) {
72+
throw $parseMinErr('isecgetset',
73+
'Defining and looking up getters and setters in Angular expressions is disallowed! '
74+
+'Expression: {0}', fullExpression);
6575
}
6676
}
6777
return obj;

test/ng/parseSpec.js

+73
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,79 @@ describe('parser', function() {
840840
expect(function() { scope.$eval('array'); }).not.toThrow();
841841
});
842842
});
843+
844+
describe('getters and setters', function() {
845+
it('should NOT allow invocation of __defineGetter__', function() {
846+
expect(function() {
847+
scope.$eval('{}.__defineGetter__("a", "".charAt)');
848+
}).toThrowMinErr(
849+
'$parse', 'isecgetset', 'Defining and looking up getters and setters in '+
850+
'Angular expressions is disallowed! Expression: '+
851+
'{}.__defineGetter__("a", "".charAt)');
852+
853+
expect(function() {
854+
scope.$eval('{}.__defineGetter__.call({}, "a", "".charAt)');
855+
}).toThrowMinErr(
856+
'$parse', 'isecgetset', 'Defining and looking up getters and setters in '+
857+
'Angular expressions is disallowed! Expression: '+
858+
'{}.__defineGetter__.call({}, "a", "".charAt)');
859+
860+
expect(function() {
861+
scope.$eval('{}["__defineGetter__"].call({}, "a", "".charAt)');
862+
}).toThrowMinErr(
863+
'$parse', 'isecgetset', 'Defining and looking up getters and setters in '+
864+
'Angular expressions is disallowed! Expression: '+
865+
'{}["__defineGetter__"].call({}, "a", "".charAt)');
866+
});
867+
868+
it('should NOT allow invocation of __defineSetter__', function() {
869+
expect(function() {
870+
scope.$eval('{}.__defineSetter__("a", "".charAt)');
871+
}).toThrowMinErr(
872+
'$parse', 'isecgetset', 'Defining and looking up getters and setters in '+
873+
'Angular expressions is disallowed! Expression: '+
874+
'{}.__defineSetter__("a", "".charAt)');
875+
876+
expect(function() {
877+
scope.$eval('{}.__defineSetter__.call({}, "a", "".charAt)');
878+
}).toThrowMinErr(
879+
'$parse', 'isecgetset', 'Defining and looking up getters and setters in '+
880+
'Angular expressions is disallowed! Expression: '+
881+
'{}.__defineSetter__.call({}, "a", "".charAt)');
882+
});
883+
884+
it('should NOT allow invocation of __lookupGetter__', function() {
885+
expect(function() {
886+
scope.$eval('{}.__lookupGetter__("a")');
887+
}).toThrowMinErr(
888+
'$parse', 'isecgetset', 'Defining and looking up getters and setters in '+
889+
'Angular expressions is disallowed! Expression: '+
890+
'{}.__lookupGetter__("a")');
891+
892+
expect(function() {
893+
scope.$eval('{}.__lookupGetter__.call({}, "a")');
894+
}).toThrowMinErr(
895+
'$parse', 'isecgetset', 'Defining and looking up getters and setters in '+
896+
'Angular expressions is disallowed! Expression: '+
897+
'{}.__lookupGetter__.call({}, "a")');
898+
});
899+
900+
it('should NOT allow invocation of __lookupSetter__', function() {
901+
expect(function() {
902+
scope.$eval('{}.__lookupSetter__("a")');
903+
}).toThrowMinErr(
904+
'$parse', 'isecgetset', 'Defining and looking up getters and setters in '+
905+
'Angular expressions is disallowed! Expression: '+
906+
'{}.__lookupSetter__("a")');
907+
908+
expect(function() {
909+
scope.$eval('{}.__lookupSetter__.call({}, "a")');
910+
}).toThrowMinErr(
911+
'$parse', 'isecgetset', 'Defining and looking up getters and setters in '+
912+
'Angular expressions is disallowed! Expression: '+
913+
'{}.__lookupSetter__.call({}, "a")');
914+
});
915+
});
843916
});
844917

845918
describe('overriding constructor', function() {

0 commit comments

Comments
 (0)