Skip to content

Commit 0bcd9dc

Browse files
Merge pull request #27 from browserify/prevent-constructor-access
disallow accessing Function constructor
2 parents 7d7bdc5 + a18a308 commit 0bcd9dc

File tree

2 files changed

+50
-3
lines changed

2 files changed

+50
-3
lines changed

index.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,13 @@ module.exports = function (ast, vars) {
101101
if((obj === FAIL) || (typeof obj == 'function')){
102102
return FAIL;
103103
}
104-
if (node.property.type === 'Identifier') {
104+
if (node.property.type === 'Identifier' && !node.computed) {
105+
if (isUnsafeProperty(node.property.name)) return FAIL;
105106
return obj[node.property.name];
106107
}
107108
var prop = walk(node.property);
108-
if (prop === FAIL) return FAIL;
109+
if (prop === null || prop === FAIL) return FAIL;
110+
if (isUnsafeProperty(prop)) return FAIL;
109111
return obj[prop];
110112
}
111113
else if (node.type === 'ConditionalExpression') {
@@ -176,3 +178,7 @@ module.exports = function (ast, vars) {
176178

177179
return result === FAIL ? undefined : result;
178180
};
181+
182+
function isUnsafeProperty(name) {
183+
return name === 'constructor' || name === '__proto__';
184+
}

test/eval.js

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,45 @@ test('MemberExpressions from Functions unresolved', function(t) {
7979
var ast = parse(src).body[0].expression;
8080
var res = evaluate(ast, {});
8181
t.equal(res, undefined);
82-
});
82+
});
83+
84+
test('disallow accessing constructor or __proto__', function (t) {
85+
t.plan(4)
86+
87+
var someValue = {};
88+
89+
var src = 'object.constructor';
90+
var ast = parse(src).body[0].expression;
91+
var res = evaluate(ast, { vars: { object: someValue } });
92+
t.equal(res, undefined);
93+
94+
var src = 'object["constructor"]';
95+
var ast = parse(src).body[0].expression;
96+
var res = evaluate(ast, { vars: { object: someValue } });
97+
t.equal(res, undefined);
98+
99+
var src = 'object.__proto__';
100+
var ast = parse(src).body[0].expression;
101+
var res = evaluate(ast, { vars: { object: someValue } });
102+
t.equal(res, undefined);
103+
104+
var src = 'object["__pro"+"t\x6f__"]';
105+
var ast = parse(src).body[0].expression;
106+
var res = evaluate(ast, { vars: { object: someValue } });
107+
t.equal(res, undefined);
108+
});
109+
110+
111+
test('constructor at runtime only', function(t) {
112+
t.plan(2)
113+
114+
var src = '(function myTag(y){return ""[!y?"__proto__":"constructor"][y]})("constructor")("console.log(process.env)")()'
115+
var ast = parse(src).body[0].expression;
116+
var res = evaluate(ast);
117+
t.equal(res, undefined);
118+
119+
var src = '(function(prop) { return {}[prop ? "benign" : "constructor"][prop] })("constructor")("alert(1)")()'
120+
var ast = parse(src).body[0].expression;
121+
var res = evaluate(ast);
122+
t.equal(res, undefined);
123+
});

0 commit comments

Comments
 (0)