| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
This is a fork of original vm2 repo. Modifications have been made to resolve CVE.
vm2 is a sandbox that can run untrusted code with whitelisted Node's built-in modules.
Try it yourself:
const vm = require('vm');
vm.runInNewContext('this.constructor.constructor("return process")().exit()');
console.log('Never gets executed.');const {VM} = require('vm2');
new VM().run('this.constructor.constructor("return process")().exit()');
// Throws ReferenceError: process is not definedIMPORTANT: VM2 requires Node.js 6 or newer.
npm install vm2const {VM} = require('vm2');
const vm = new VM();
vm.run(`process.exit()`); // TypeError: process.exit is not a functionconst {NodeVM} = require('vm2');
const vm = new NodeVM({
require: {
external: true,
root: './'
}
});
vm.run(`
var request = require('request');
request('http://www.google.com', function (error, response, body) {
console.error(error);
if (!error && response.statusCode == 200) {
console.log(body); // Show the HTML for the Google homepage.
}
});
`, 'vm.js');VM is a simple sandbox to synchronously run untrusted code without the require feature. Only JavaScript built-in objects and Node's Buffer are available. Scheduling functions (setInterval, setTimeout and setImmediate) are not available by default.
Options:
IMPORTANT: Timeout is only effective on synchronous code that you run through run. Timeout does NOT work on any method returned by VM. There are some situations when timeout doesn't work - see #244.
const {VM} = require('vm2');
const vm = new VM({
timeout: 1000,
allowAsync: false,
sandbox: {}
});
vm.run('process.exit()'); // throws ReferenceError: process is not definedYou can also retrieve values from VM.
let number = vm.run('1337'); // returns 1337TIP: See tests for more usage examples.
Unlike VM, NodeVM allows you to require modules in the same way that you would in the regular Node's context.
Options:
IMPORTANT: Timeout is not effective for NodeVM so it is not immune to while (true) {} or similar evil.
REMEMBER: The more modules you allow, the more fragile your sandbox becomes.
const {NodeVM} = require('vm2');
const vm = new NodeVM({
console: 'inherit',
sandbox: {},
require: {
external: true,
builtin: ['fs', 'path'],
root: './',
mock: {
fs: {
readFileSync: () => 'Nice try!'
}
}
}
});
// Sync
let functionInSandbox = vm.run('module.exports = function(who) { console.log("hello "+ who); }');
functionInSandbox('world');
// Async
let functionWithCallbackInSandbox = vm.run('module.exports = function(who, callback) { callback("hello "+ who); }');
functionWithCallbackInSandbox('world', (greeting) => {
console.log(greeting);
});When wrapper is set to none, NodeVM behaves more like VM for synchronous code.
assert.ok(vm.run('return true') === true);TIP: See tests for more usage examples.
To load modules by relative path, you must pass the full path of the script you're running as a second argument to vm's run method if the script is a string. The filename is then displayed in any stack traces generated by the script.
vm.run('require("foobar")', '/data/myvmscript.js');If the script you are running is a VMScript, the path is given in the VMScript constructor.
const script = new VMScript('require("foobar")', {filename: '/data/myvmscript.js'});
vm.run(script);A resolver can be created via makeResolverFromLegacyOptions and be used for multiple NodeVM instances allowing to share compiled module code potentially speeding up load times. The first example of NodeVM can be rewritten using makeResolverFromLegacyOptions as follows.
const resolver = makeResolverFromLegacyOptions({
external: true,
builtin: ['fs', 'path'],
root: './',
mock: {
fs: {
readFileSync: () => 'Nice try!'
}
}
});
const vm = new NodeVM({
console: 'inherit',
sandbox: {},
require: resolver
});You can increase performance by using precompiled scripts. The precompiled VMScript can be run multiple times. It is important to note that the code is not bound to any VM (context); rather, it is bound before each run, just for that run.
const {VM, VMScript} = require('vm2');
const vm = new VM();
const script = new VMScript('Math.random()');
console.log(vm.run(script));
console.log(vm.run(script));It works for both VM and NodeVM.
const {NodeVM, VMScript} = require('vm2');
const vm = new NodeVM();
const script = new VMScript('module.exports = Math.random()');
console.log(vm.run(script));
console.log(vm.run(script));Code is compiled automatically the first time it runs. One can compile the code anytime with script.compile(). Once the code is compiled, the method has no effect.
Errors in code compilation and synchronous code execution can be handled by try-catch. Errors in asynchronous code execution can be handled by attaching uncaughtException event handler to Node's process.
try {
var script = new VMScript('Math.random()').compile();
} catch (err) {
console.error('Failed to compile script.', err);
}
try {
vm.run(script);
} catch (err) {
console.error('Failed to execute script.', err);
}
process.on('uncaughtException', (err) => {
console.error('Asynchronous error caught.', err);
});You can debug or inspect code running in the sandbox as if it was running in a normal process.
/tmp/main.js:
const {VM, VMScript} = require('.');
const fs = require('fs');
const file = `${__dirname}/sandbox.js`;
// By providing a file name as second argument you enable breakpoints
const script = new VMScript(fs.readFileSync(file), file);
new VM().run(script);/tmp/sandbox.js
const foo = 'ahoj';
// The debugger keyword works just fine everywhere.
// Even without specifying a file name to the VMScript object.
debugger;To prevent sandboxed scripts from adding, changing, or deleting properties from the proxied objects, you can use freeze methods to make the object read-only. This is only effective inside VM. Frozen objects are affected deeply. Primitive types cannot be frozen.
Example without using freeze:
const util = {
add: (a, b) => a + b
}
const vm = new VM({
sandbox: {util}
});
vm.run('util.add = (a, b) => a - b');
console.log(util.add(1, 1)); // returns 0Example with using freeze:
const vm = new VM(); // Objects specified in the sandbox cannot be frozen.
vm.freeze(util, 'util'); // Second argument adds object to global.
vm.run('util.add = (a, b) => a - b'); // Fails silently when not in strict mode.
console.log(util.add(1, 1)); // returns 2IMPORTANT: It is not possible to freeze objects that have already been proxied to the VM.
Unlike freeze, this method allows sandboxed scripts to add, change, or delete properties on objects, with one exception - it is not possible to attach functions. Sandboxed scripts are therefore not able to modify methods like toJSON, toString or inspect.
IMPORTANT: It is not possible to protect objects that have already been proxied to the VM.
const assert = require('assert');
const {VM} = require('vm2');
const sandbox = {
object: new Object(),
func: new Function(),
buffer: new Buffer([0x01, 0x05])
}
const vm = new VM({sandbox});
assert.ok(vm.run(`object`) === sandbox.object);
assert.ok(vm.run(`object instanceof Object`));
assert.ok(vm.run(`object`) instanceof Object);
assert.ok(vm.run(`object.__proto__ === Object.prototype`));
assert.ok(vm.run(`object`).__proto__ === Object.prototype);
assert.ok(vm.run(`func`) === sandbox.func);
assert.ok(vm.run(`func instanceof Function`));
assert.ok(vm.run(`func`) instanceof Function);
assert.ok(vm.run(`func.__proto__ === Function.prototype`));
assert.ok(vm.run(`func`).__proto__ === Function.prototype);
assert.ok(vm.run(`new func() instanceof func`));
assert.ok(vm.run(`new func()`) instanceof sandbox.func);
assert.ok(vm.run(`new func().__proto__ === func.prototype`));
assert.ok(vm.run(`new func()`).__proto__ === sandbox.func.prototype);
assert.ok(vm.run(`buffer`) === sandbox.buffer);
assert.ok(vm.run(`buffer instanceof Buffer`));
assert.ok(vm.run(`buffer`) instanceof Buffer);
assert.ok(vm.run(`buffer.__proto__ === Buffer.prototype`));
assert.ok(vm.run(`buffer`).__proto__ === Buffer.prototype);
assert.ok(vm.run(`buffer.slice(0, 1) instanceof Buffer`));
assert.ok(vm.run(`buffer.slice(0, 1)`) instanceof Buffer);Before you can use vm2 in the command line, install it globally with npm install vm2 -g.
vm2 ./script.js| Back | FazBrowse Home | New Git URL |