No longer maintained. Do not use.
mmckegg / notevil Goto Github PK
View Code? Open in Web Editor NEWEvalulate javascript like the built-in javascript eval() method but safely.
Evalulate javascript like the built-in javascript eval() method but safely.
No longer maintained. Do not use.
I know right now it's solved by iteration counter, but it might not be enough, or something you don't ecxactly need
I think adding optional parameter would be good option, but checking if time is out after each operation might be waste of resources. Maybe wrapping it in worker would be better solution?
I will try to prepare a pull request with that feature.
includes infinite recursion
source from esprima
function () {
var name, types = {};
if (typeof Object.create === 'function') {
types = Object.create(null);
}
for (name in Syntax) {
if (Syntax.hasOwnProperty(name)) {
types[name] = Syntax[name]; //gets stuck here. object is 'types'.
}
}
if (typeof Object.freeze === 'function') {
Object.freeze(types);
}
return types;
}()
Even though some other instantiation code works, like new Number()
, when new Date()
is evaluated it returns 'Invalid Date'
.
For example:
notevil('new Date()'); // returns 'Invalid Date'
var safeEval = require('notevil')
safeEval('y.u.no.error')
//=> undefined
safeEval('y.u.no.error', {})
//=> undefined
safeEval('y.u.no.error',{y:null})
//=> TypeError: Cannot read property 'u' of null
safeEval('y.u.no.error',{y:undefined})
//=> TypeError: Cannot read property 'u' of undefined
I have a project that interprets inline JS like this:
$: var key = "val";
Is there a way to expose 'key' to a provided context when evaling?
This is what I'm hoping for:
var ctx = {};
notevil('let x = 0;', ctx);
console.log(ctx.x);
//0
Obviously I could require the developer to return an object with the exposed variable names like this:
var code = `
let x = 10;
Object({ x }); //expose everything wrapped here
`;
I would have to do my own mixin on the ctx
object and it would be a valid workaround. It's just more work for my developers.
Types should be exposed by default. Since their literals are exposed the types are already exposed through round-about means. I would consider any type that has a literal to be a basic and essential 'Language Feature'. These structures could still be overwritten via the included context hash.
Array = [].constructor
Object = ({}).constructor
String = "".constructor
failing types tests here: #12
I think these can be cannibalized
https://github.com/int3/closure-interpreter/tree/master/tests
Despite the fact that closure-interpreter passes those tests, Array.map
still fails
int3/closure-interpreter#1
Let user set maxIterations
of InfiniteChecker
.
var result = safeEval('function loop() {while(1) {}}', {
maxIterations: 1000000
});
Hi there,
I couldn't find a SECURITY.md
in your repository and am not sure how to best contact you privately to disclose a security issue.
Can you add a SECURITY.md
file with an e-mail to your repository, so that our system can send you the vulnerability details? GitHub suggests that a security policy is the best way to make sure security issues are responsibly disclosed.
Once you've done that, you should receive an e-mail within the next hour with more info.
Thanks! (cc @huntr-helper)
naïve hoisting causes problem when attempting to safeEval the following code
var names = [ ... ]
var primitives = names.map(getGlobal);
function getGlobal(){ ... }
Here is this project's own primitives.js
after hoisting
{
var global = self;
var names = [
'Object',
'String',
'Boolean',
'Number',
'RegExp',
'Date',
'Array'
];
var immutable = {
string: 'String',
boolean: 'Boolean',
number: 'Number'
};
var primitives = names.map(getGlobal);
var protos = primitives.map(getProto);
var protoReplacements = {};
module.exports = Primitives;
function Primitives(context) {
if (this instanceof Primitives) {
this.context = context;
for (var i = 0; i < names.length; i++) {
if (!this.context[names[i]]) {
this.context[names[i]] = wrap(primitives[i]);
}
}
} else {
return new Primitives(context);
}
}
Primitives.prototype.replace = function (value) {
var primIndex = primitives.indexOf(value);
var protoIndex = protos.indexOf(value);
if (~primIndex) {
var name = names[primIndex];
return this.context[name];
} else if (~protoIndex) {
var name = names[protoIndex];
return this.context[name].prototype;
} else {
return value;
}
};
Primitives.prototype.getPropertyObject = function (object, property) {
if (immutable[typeof object]) {
return this.getPrototypeOf(object);
}
return object;
};
Primitives.prototype.isPrimative = function (value) {
return !!~primitives.indexOf(value) || !!~protos.indexOf(value);
};
Primitives.prototype.getPrototypeOf = function (value) {
if (value == null) {
return value;
}
var immutableType = immutable[typeof value];
if (immutableType) {
var proto = this.context[immutableType].prototype;
} else {
var proto = Object.getPrototypeOf(value);
}
if (!proto || proto === Object.prototype) {
return null;
} else {
var replacement = this.replace(proto);
if (replacement === value) {
replacement = this.replace(Object.prototype);
}
return replacement;
}
};
function getProto(func) {
return func.prototype;
}
function getGlobal(str) {
return global[str];
}
function setProto(obj, proto) {
obj.__proto__ = proto;
}
function wrap(prim) {
var proto = Object.create(prim.prototype);
var result = function () {
if (this instanceof result) {
prim.apply(this, arguments);
} else {
var instance = prim.apply(null, arguments);
setProto(instance, proto);
return instance;
}
};
setProto(result, prim);
result.prototype = proto;
return result;
}
}
I have an example object here that you can use reproduce this error
var r=[{
"_id": "BLOCKS",
"type": "cache",
"cache": {
"0000000000260dfd032cb5bc302a3307fe141c7e505b53214a6b7c1703ab9b6b": {
"height": 1087605,
"block": "confirmed-block",
"from": "blockio_blk"
},
"00000000000004e108a232adc26102f18388762f18d459952177f486918bbf3f": {
"height": 1087607,
"block": "confirmed-block",
"from": "blockio_blk"
},
"00000000004e2a0b541e5a95f6e714e75dcf89964a69bfc34bf615465ef04a74": {
"height": 1087606,
"block": "confirmed-block",
"from": "blockio_blk"
},
"00000000a8fc15b379ab82bf3ad04c92b26995c679596cc52ce47791dc751028": {
"height": 1087608,
"block": "confirmed-block",
"from": "blockio_blk"
},
"0000000000000255c45f107736f106a4c56d33bb585b3b6f506f8189dafd1330": {
"height": 1087609,
"block": "confirmed-block",
"from": "blockio_blk"
},
}
}];
Normal eval works fine:
eval('for(var i in r[0].cache){if(r[0].cache[i].height>5){delete r[0].cache[i];}}');
console.log(r);
[ { _id: 'BLOCKS', type: 'cache', cache: {} } ]
notevail gets error
require('notevil')('for(var i in r[0].cache){if(r[0].cache[i].height>5){delete r[0].cache[i];}}',{r:r});
Error: Unsupported expression: UnaryExpression
at unsupportedExpression (/var/sentora/hostdata/zadmin/node_modules/notevil/index.js:416:13)
at walk (/var/sentora/hostdata/zadmin/node_modules/notevil/index.js:260:27)
at walk (/var/sentora/hostdata/zadmin/node_modules/notevil/index.js:103:16)
at walkAll (/var/sentora/hostdata/zadmin/node_modules/notevil/index.js:61:16)
at walk (/var/sentora/hostdata/zadmin/node_modules/notevil/index.js:79:22)
at walk (/var/sentora/hostdata/zadmin/node_modules/notevil/index.js:161:18)
at walkAll (/var/sentora/hostdata/zadmin/node_modules/notevil/index.js:61:16)
at walk (/var/sentora/hostdata/zadmin/node_modules/notevil/index.js:79:22)
at walk (/var/sentora/hostdata/zadmin/node_modules/notevil/index.js:207:19)
at walkAll (/var/sentora/hostdata/zadmin/node_modules/notevil/index.js:61:16)
The error object looks like
"error": {
"node": {
"type": "UnaryExpression",
"operator": "delete",
"argument": {
"type": "MemberExpression",
"computed": true,
"object": {
"type": "MemberExpression",
"computed": false,
"object": {
"type": "MemberExpression",
"computed": true,
"object": {
"type": "Identifier",
"name": "r"
},
"property": {
"type": "Literal",
"value": 0
}
},
"property": {
"type": "Identifier",
"name": "cache"
}
},
"property": {
"type": "Identifier",
"name": "i"
}
},
"prefix": true
}
For example:
var condition = (1 in [1,2,3]);
Need to check the condition as safeEval(condition);
This above statement is execute or not.
Can someone help me out?
Some missing Assignment Operators
*=
/=
%=
I don't need them right now but they are missing
"new Boolean(true)"
├─ type: Program
└─ body
└─ 0
├─ type: ExpressionStatement
└─ expression
├─ type: NewExpression
├─ callee
│ ├─ type: Identifier
│ └─ name: Boolean
└─ arguments
└─ 0
├─ type: Literal
└─ value: true
Am I able to completely block everything, even while loops? I want an environment with everything that can be ran explicitly approved.
The left-hand side of the &&
expression fails, so it should skip the right-hand side and return.
if (typeof define === 'function' && define.amd) {
safeEval('var result = 0; [1,2,3,4].forEach(function(item){ result += item }); result')
// result still 0, eval() returns 10
I'm trying to use this library in a typescript project. But typescript/rollup throws error during compilation step.
Is there any plan to support typescript?
var code = '[1,2,3,4].map(function(item){ return item*100 })'
safeEval(code)
//=> undefined
eval(code)
//=> [100, 200, 300, 400]
safeEval('this')
//=> Object {type: "ThisExpression"} index.js:11
//=> Uncaught Error: Unsupported expression.
Not sure what should happen, but thought I should open an issue to discuss.
When user is downloading a large js, this module can compile it on the fly.
This is vunerable to evil regular expressions. It's possible to construct a regular expression that executes in exponential time, which won't look like an obvious infinite loop, but will lock the cpu for a while.
require('notevil')("/((a+)+)b/.test('aaaaaaaaaaaaaaaaaaaaaaaaaaaaa')")
This tricks the regex evaluator into searching for all possible ways to arrange the two nested a
groups,
(since the string is missing a b
at the end it will continue searching, if it had a b
it would return as soon as it has found a match)
the simplest way to prevent this is just to block regular expressions with a starheight > 1 (i.e. with nested groups) this may block some non-evil regular expressions, but is much simpler than implementing a regular expression interpreter.
for more detail: http://perlgeek.de/blog-en/perl-tips/in-search-of-an-exponetial-regexp.html
also, @substack has a module for detecting safe regular expressions: https://github.com/substack/safe-regex
Exist a way to use destructured assignments inside script with notevil ?
ex:
const { e,__value} = EVENT;
if(e){
SELF.VALUE=__value;
}
SELF.VALUE;
const safeEval = require('notevil');
const source = `
return inputs.map((v) => v + 1);
`;
try {
const h = safeEval.Function('inputs', source);
const o = h([1, 2, 3]);
conosle.log('===', o);
} catch(err) {
console.log(err);
}
===, [ 2, 3, 4 ]
{ Error: Line 2: Unexpected token >
at throwError (/Users/adoyle/Workspace/Ali/wormholes-system-plugins/node_modules/[email protected]@esprima/esprima.js:1156:21)
at throwUnexpected (/Users/adoyle/Workspace/Ali/wormholes-system-plugins/node_modules/[email protected]@esprima/esprima.js:1213:9)
at parsePrimaryExpression (/Users/adoyle/Workspace/Ali/wormholes-system-plugins/node_modules/[email protected]@esprima/esprima.js:1567:16)
at parseLeftHandSideExpressionAllowCall (/Users/adoyle/Workspace/Ali/wormholes-system-plugins/node_modules/[email protected]@esprima/esprima.js:1644:61)
at parsePostfixExpression (/Users/adoyle/Workspace/Ali/wormholes-system-plugins/node_modules/[email protected]@esprima/esprima.js:1703:20)
at parseUnaryExpression (/Users/adoyle/Workspace/Ali/wormholes-system-plugins/node_modules/[email protected]@esprima/esprima.js:1784:16)
at parseMultiplicativeExpression (/Users/adoyle/Workspace/Ali/wormholes-system-plugins/node_modules/[email protected]@esprima/esprima.js:1790:20)
at parseAdditiveExpression (/Users/adoyle/Workspace/Ali/wormholes-system-plugins/node_modules/[email protected]@esprima/esprima.js:1807:20)
at parseShiftExpression (/Users/adoyle/Workspace/Ali/wormholes-system-plugins/node_modules/[email protected]@esprima/esprima.js:1824:20)
at parseRelationalExpression (/Users/adoyle/Workspace/Ali/wormholes-system-plugins/node_modules/[email protected]@esprima/esprima.js:1845:16)
index: 41, lineNumber: 2, column: 28 }
node version: v6.9.1
I'm currently trying to implement notevil 1.1.0 into Vue to create a Vue 2.6-csp build. However I'm running into the fact that with statements are used in Vue and notevil throws an error for these statements: https://github.com/mmckegg/notevil/blob/master/index.js#L368
In Vue I am able to find the following code which probably triggers this (https://github.com/vuejs/vue/blob/2.6/src/compiler/codegen/index.js#L49):
with(this){return ${code}}
And somewhere in the code following where that line is executed by:
return new Function(code)
Which I have tried to replace with:
const fn = notevil.Function(code);
return function() {
return fn.call(this);
};
Where I have tried to inject the this property to be used in the with(this)
expression.
The result is a Unexpected expression: 'WithStatement'
error in my console.
Is it possible to add the ability to parse with statements? Or does anyone have suggestions on how to work around the with(this) expressions?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.