58

I would like to have the ability to let users submit arbitrary JavaScript code, which is then sent to a Node.JS server and safely executed before the output is sent back to multiple clients (as JSON). The eval function comes to mind, but I know this has multiple security concerns (the user submitted code would be able to access Node's File API, etc). I have seen some projects like Microsoft Web Sandbox and Google Caja which allow execution of sanitized markup and script (for embedding third-party ads on websites), but it seems that these are client-side tools and I'm not sure if they can be safely used within Node.

Is there a standard way to sandbox and execute non-trusted JavaScript in Node, getting the output. Is it a mistake to try and do this server-side?

EDIT: It's not important that the user be able to leverage the full capabilities of JavaScript, in fact it would be preferable to be able to pick and choose which APIs would be provided to the user code.

EDIT: I am going to go ahead and update with what I found. This Sandcastle module (bcoe/sandcastle) seems to aim to do what I have in mind. Not sure how secure it is, but since I this is not for anything too important I think I'll if try it. I'll add my own answer if I'm able to successfully do this.

Cory Gross
  • 36,833
  • 17
  • 68
  • 80
  • Why does it have to execute on your server, rather than on the client? –  Jul 07 '13 at 14:56
  • 3
    I think this is a mistake, but you could try the node 'vm' stuff--http://nodejs.org/api/vm.html – JoshRagem Jul 07 '13 at 14:57
  • 2
    This is for a programming game concept for fun, I can't trust the clients to execute the code. I want to do it server side for that reason and because the output will be serialized and sent to 1 or more other clients. It looks like the vm module or something wrapping it is what I want. – Cory Gross Jul 07 '13 at 16:23
  • 5
    @CoryGross Did you find any vulnerabilities with sandcastle or sandbox? I am building something similar (allow users to submit js code) and your input would help me a lot :) – Khaja Minhajuddin Apr 08 '14 at 07:40
  • 3
    There's a similar question (but older) with an interesting accepted answer (mentions some important issues) here: http://stackoverflow.com/questions/7446729/how-to-run-user-submitted-scripts-securely-in-a-node-js-sandbox – Akhorus Apr 20 '15 at 13:53
  • 2
    I'm interested in how did you solved it. I had a similar question: http://stackoverflow.com/questions/32773981/safe-way-to-let-users-register-handelbars-helpers-in-nodejs-solved I "solved" it using VM, I'm still testing if there is any way to exploit my solution. – Marcos Casagrande Sep 30 '15 at 01:54
  • Does this answer your question? [How to run untrusted code serverside?](https://stackoverflow.com/questions/10937870/how-to-run-untrusted-code-serverside) – Jerska Mar 27 '20 at 10:36

5 Answers5

14

You can use sandbox support in nodejs with vm.runInContext('js code', context), sample in api documentation:

https://nodejs.org/api/vm.html#vm_vm_runinthiscontext_code_options

const util = require('util');
const vm = require('vm');

const sandbox = { globalVar: 1 };
vm.createContext(sandbox);

for (var i = 0; i < 10; ++i) {
    vm.runInContext('globalVar *= 2;', sandbox);
}
console.log(util.inspect(sandbox));

// { globalVar: 1024 }

WARN: As pointed by "s4y" it seems to be flawled. Please look at the comments.

ton
  • 3,827
  • 1
  • 42
  • 40
  • 4
    This doesn't seem to be safe, e.g.: `vm.runInNewContext('this.constructor.constructor("return process")().exit()');` (from the vm2 README: https://github.com/patriksimek/vm2). – s4y Apr 17 '17 at 00:40
  • Is there any protection against infinite loops? – Qwertiy Jun 09 '18 at 09:36
  • @Qwertiy you can use timeout in milliseconds like this `vm.runInNewContext(`while (true) 1`, {}, {timeout: 1000});`. – Serg Oct 25 '18 at 09:33
8

One alternative would be to use http://github.com/patriksimek/vm2:

$ npm install vm2

then:

const {VM} = require('vm2');
const vm = new VM();

vm.run(`1 + 1`);  // => 2

as mentioned in comments of other answers.

I don't know how secure it is, but it at least claims that it runs untrusted code securely (in its README). And I couldn't find any obvious security issues so far as solutions suggested in other answers here.

Hiroshi Ichikawa
  • 616
  • 9
  • 10
5

This answer is outdated as gf3 does not provide protection against sandbox breaking

http://gf3.github.io/sandbox/ - it uses require('child_process') instead of require('vm').

Ginden
  • 5,149
  • 34
  • 68
  • I am going to go ahead and accept, I will be looking at both sandbox and the sandcastle module I linked to above over the next few days. Thanks. – Cory Gross Jul 12 '13 at 03:00
  • 2
    Don't mislead, gf3/sandbox uses both child process and vm modules, check the code. And all sandboxing solutions do the same. – Alexander Ulitin Nov 12 '13 at 17:28
  • 8
    For future viewers, currently as it stands gf3 is exploitable and can be broken out of. – Tom C Aug 31 '15 at 03:10
  • 3
    Caution! gf3/sandbox hasn't been updated in 1 year, and there's still an open issue where the sandbox can be broken out of: https://github.com/gf3/sandbox/issues/29 – GladstoneKeep Sep 12 '15 at 15:50
5

Under Node.js you may create a sandboxed child process, but you also need to append the code with "use strict";, otherwise it is possible to break the sandbox with arguments.callee.caller.

Not sure why you need to send it to the server, because the code may also be executed in a sandboxed web-worker.

Also take a look at my Jailed library which simplifies everything just mentioned for both Node.js and web-browser, and additionally provides an opportunity to export a set of functions into the sandbox.

asvd
  • 944
  • 10
  • 16
  • 4
    At this time, Jailed is broken: https://github.com/asvd/jailed/issues/33 – arve0 Jul 27 '16 at 01:06
  • @arve0 you are right, jailed was compromised under node, the fix is being prepared – asvd Jul 28 '16 at 08:39
  • 3
    Alternative: https://github.com/patriksimek/vm2 Seem to be safe, but seing the log potential break outs, I would be careful. – arve0 Jul 28 '16 at 12:51
2

Depending on your usage, I'd suggest you also consider protecting your sandbox with a virtual environment like gVisor. You can find some info here.

Pål Thingbø
  • 1,211
  • 1
  • 17
  • 17