diff --git a/index.js b/index.js index ea16186..7620e5b 100644 --- a/index.js +++ b/index.js @@ -101,11 +101,13 @@ module.exports = function (ast, vars) { if((obj === FAIL) || (typeof obj == 'function')){ return FAIL; } - if (node.property.type === 'Identifier') { + if (node.property.type === 'Identifier' && !node.computed) { + if (isUnsafeProperty(node.property.name)) return FAIL; return obj[node.property.name]; } var prop = walk(node.property); - if (prop === FAIL) return FAIL; + if (prop === null || prop === FAIL) return FAIL; + if (isUnsafeProperty(prop)) return FAIL; return obj[prop]; } else if (node.type === 'ConditionalExpression') { @@ -176,3 +178,7 @@ module.exports = function (ast, vars) { return result === FAIL ? undefined : result; }; + +function isUnsafeProperty(name) { + return name === 'constructor' || name === '__proto__'; +} diff --git a/test/eval.js b/test/eval.js index c8d3d25..4055b35 100644 --- a/test/eval.js +++ b/test/eval.js @@ -79,4 +79,45 @@ test('MemberExpressions from Functions unresolved', function(t) { var ast = parse(src).body[0].expression; var res = evaluate(ast, {}); t.equal(res, undefined); -}); \ No newline at end of file +}); + +test('disallow accessing constructor or __proto__', function (t) { + t.plan(4) + + var someValue = {}; + + var src = 'object.constructor'; + var ast = parse(src).body[0].expression; + var res = evaluate(ast, { vars: { object: someValue } }); + t.equal(res, undefined); + + var src = 'object["constructor"]'; + var ast = parse(src).body[0].expression; + var res = evaluate(ast, { vars: { object: someValue } }); + t.equal(res, undefined); + + var src = 'object.__proto__'; + var ast = parse(src).body[0].expression; + var res = evaluate(ast, { vars: { object: someValue } }); + t.equal(res, undefined); + + var src = 'object["__pro"+"t\x6f__"]'; + var ast = parse(src).body[0].expression; + var res = evaluate(ast, { vars: { object: someValue } }); + t.equal(res, undefined); +}); + + +test('constructor at runtime only', function(t) { + t.plan(2) + + var src = '(function myTag(y){return ""[!y?"__proto__":"constructor"][y]})("constructor")("console.log(process.env)")()' + var ast = parse(src).body[0].expression; + var res = evaluate(ast); + t.equal(res, undefined); + + var src = '(function(prop) { return {}[prop ? "benign" : "constructor"][prop] })("constructor")("alert(1)")()' + var ast = parse(src).body[0].expression; + var res = evaluate(ast); + t.equal(res, undefined); +});