Permalink
Browse files

More security fixes + unit tests

  • Loading branch information...
josdejong committed Mar 31, 2017
1 parent 43c4fe9 commit 3c3517daa6412457826b79b60368d8e8e415a7dd
Showing with 56 additions and 10 deletions.
  1. +5 −0 HISTORY.md
  2. +15 −2 lib/expression/node/FunctionNode.js
  3. +36 −8 test/expression/parse.test.js
View
@@ -1,6 +1,11 @@
# History
+## 2017-03-31, version 3.10.3
+
+- More security fixes related to the ones fixed in `v3.10.2`.
+
+
## 2017-03-31, version 3.10.2
- Fixed a security vulnerability in the expression parser allowing
@@ -428,19 +428,32 @@ function factory (type, config, load, typed, math) {
* else throws an error
*/
function customs (fn) {
+ if (fn === jsEval) {
+ throw new Error('Calling "eval" is not allowed');
+ }
+
if (fn === Function) {
throw new Error('Calling "Function" is not allowed');
}
- if (fn === jsEval) {
- throw new Error('Calling "eval" is not allowed');
+ if (fn === Function.apply) {
+ throw new Error('Calling "apply" is not allowed');
+ }
+
+ if (fn === Function.call) {
+ throw new Error('Calling "call" is not allowed');
+ }
+
+ if (fn === Function.bind) {
+ throw new Error('Calling "bind" is not allowed');
}
// this function is ok
return fn;
}
var jsEval = eval
+var jsApply = eval

This comment has been minimized.

Show comment
Hide comment
@eirmag

eirmag Apr 2, 2017

Quick question, what is the use of this declared but never used variable?

@eirmag

eirmag Apr 2, 2017

Quick question, what is the use of this declared but never used variable?

This comment has been minimized.

Show comment
Hide comment
@josdejong

josdejong Apr 2, 2017

Owner

Thanks for checking out the code. This is just a sloppy left-over, I've removed it.

@josdejong

josdejong Apr 2, 2017

Owner

Thanks for checking out the code. This is just a sloppy left-over, I've removed it.

exports.name = 'FunctionNode';
exports.path = 'expression.node';
@@ -2043,28 +2043,56 @@ describe('parse', function() {
describe('security', function () {
- it ('should not allow calling Function from an object property', function () {
+ it ('should not allow calling Function/eval via a symbol', function () {
assert.throws(function () {
- math.eval('[].map.constructor("console.log(\\"hacked...\\")")()')
+ math.eval('disguised("console.log(\\"hacked...\\")")()', {disguised: eval})
+ }, /Error: Calling "eval" is not allowed/)
+
+ assert.throws(function () {
+ math.eval('disguised("console.log(\\"hacked...\\")")()', {disguised: Function})
}, /Error: Calling "Function" is not allowed/)
})
- it ('should not allow calling Function', function () {
+ it ('should not allow calling Function/eval via an object property', function () {
+ assert.throws(function () {
+ math.eval('[].map.constructor("console.log(\\"hacked...\\")")()')
+ }, /Error: Calling "Function" is not allowed/)
+
+ assert.throws(function () {
+ math.eval('obj.disguised("console.log(\\"hacked...\\")")()', {obj: {disguised: eval}})
+ }, /Error: Calling "eval" is not allowed/)
+
assert.throws(function () {
- math.eval('disguised("console.log(\\"hacked...\\")")()', {disguised: Function})
math.eval('obj.disguised("console.log(\\"hacked...\\")")()', {obj: {disguised: Function}})
- math.eval('fn()("console.log(\\"hacked...\\")")()', {fn: function () {return Function}})
}, /Error: Calling "Function" is not allowed/)
})
- it ('should not allow calling eval', function () {
+ it ('should not allow calling Function/eval when returned by a function', function () {
+ assert.throws(function () {
+ math.eval('fn()("console.log(\\"hacked...\\")")()', {fn: function () {return Function}})
+ }, /Error: Calling "Function" is not allowed/)
+
assert.throws(function () {
- math.eval('disguised("console.log(\\"hacked...\\")")()', {disguised: eval})
- math.eval('obj.disguised("console.log(\\"hacked...\\")")()', {obj: {disguised: eval}})
math.eval('fn()("console.log(\\"hacked...\\")")()', {fn: function () {return eval}})
}, /Error: Calling "eval" is not allowed/)
})
+ it ('should not allow calling Function/eval via call/apply', function () {
+ assert.throws(function () {
+ math.eval('[].map.constructor.call(null, "console.log(\\"hacked...\\")")()')
+ }, /Error: Calling "call" is not allowed/)
+
+ assert.throws(function () {
+ math.eval('[].map.constructor.apply(null, ["console.log(\\"hacked...\\")"])()')
+ }, /Error: Calling "apply" is not allowed/)
+ })
+
+ it ('should not allow calling Function/eval via bind', function () {
+ assert.throws(function () {
+ math.eval('[].map.constructor.bind()("console.log(\\"hacked...\\")")()')
+ }, /Error: Calling "bind" is not allowed/)
+ })
+
});
});

0 comments on commit 3c3517d

Please sign in to comment.