Skip to content
Patrik Simek edited this page Jun 16, 2016 · 1 revision

1.x to 2.x changes

Buffer class is no longer globally available by default in NodeVM. To make Buffer accessible globaly, enable require option and make sure buffer module is whitelisted. More info in Known Issues.

VM

VM is a simple sandbox, without require feature, to synchronously run an untrusted code. Only JavaScript built-in objects are available.

Options:

  • timeout - Script timeout in milliseconds.
  • sandbox - VM's global object.
  • language - javascript (default) or coffeescript
var VM = require('vm2').VM;

var options = {
    timeout: 1000,
    sandbox: {}
};

var vm = new VM(options);
vm.run("process.exit()"); // throws ReferenceError: process is not defined

You can also retrieve values from VM.

var number = vm.run("1337"); // returns 1337

IMPORTANT: Timeout is only effective on code you run through run. Timeout is NOT effective on any method returned by VM.

NodeVM

Unlike VM, NodeVM lets you require modules same way like in regular Node's context.

Options:

  • console - inherit to enable console, redirect to redirect to events, off to disable console (default: inherit)
  • sandbox - VM's global object
  • language - javascript (default) or coffeescript
  • require - true to enable require method (default: false)
  • requireExternal - true to enable require of external modules (default: false)
  • requireNative - Array of allowed native modules. (default: all available)
  • requireRoot - Restricted path where local modules can be required (default: every path)
  • useStrict - Whether to add use strict directive to required modules (default: true)

Available modules: assert, buffer, child_process, constants, crypto, tls, dgram, dns, http, https, net, punycode, querystring, url, domain, events, fs, path, os, stream, string_decoder, timers, tty, util, sys, vm, zlib

REMEMBER: The more modules you allow, the more fragile your sandbox becomes.

IMPORTANT: Timeout is not effective for NodeVM so it is not immune to while (true) {} or similar evil.

var NodeVM = require('vm2').NodeVM;

var options = {
	console: 'inherit',
    sandbox: {},
    require: true,
    requireExternal: true,
    requireNative: ['fs', 'path'],
    requireRoot : "./"
};

var vm = new NodeVM(options);
var functionInSandbox = vm.run("module.exports = function(who) { console.log('hello '+ who); }");

Calling VM's methods

Securely call method in sandbox. All arguments except functions are cloned during the process to prevent context leak. Functions are wrapped to secure closures. Buffers are copied.

IMPORTANT: Method doesn't check for circular objects! If you send a circular structure as an argument, your process will get stuck in infinite loop.

IMPORTANT: Always use vm.call method to call methods or callbacks in sandbox. If you call it directly, you are exposing yourself a risk of main global context leakage!

vm.call(functionInSandbox, 'world');

Loading modules by relative path

To load modules by relative path, you must pass full path of the script you're running as a second argument of vm's run method. Filename then also shows up in any stack traces produced from the script.

vm.run("require('foobar')", "/data/myvmscript.js");

CLI

Before you can use vm2 in command line, install it globally with npm install vm2 -g.

$ vm2 ./script.js

Known Issues

Allowing buffer to be required inside NodeVM may crash your app with TypeError: Invalid non-string/buffer chunk errors (reported here and here). To prevent buffer from loading, disable require option or remove buffer from list of whitelisted native modules. Keep in mind that modules like fs or stream do require buffer internally.