66

What are the options for running (possibly malicious) user-submitted scripts in node.js, securely? I.e. in an environment that prevents code from accessing sensitive data and APIs?

vm.runInNewContext(userScript, {}) is a tempting starting point... but it seems like there are known issues there.

The sandbox module looks interesting, but uses runInNewContext() as well so I'm a bit leery of it.

4
  • I'd recommend using vm because it's part of node core. And since node core tends to gets its bugs fixed just assume it the issue will be fixed Commented Sep 17, 2011 at 0:39
  • @Raynos it's not a bug. The docs say it's only intended for known-good code. Commented Oct 30, 2011 at 9:02
  • @thejh - true, but the API does lend itself toward the pretty reasonable belief that the code is executing in an entirely different context, implying that said code shouldn't be able to access the current context. And I expect that the intent of the API is exactly that - to provide a sandbox in which to run scripts. So... I think a pretty strong case can be made that this is simply a well-documented bug. :) Commented Oct 30, 2011 at 22:54
  • Does this answer your question? How to run untrusted code serverside? Commented Mar 27, 2020 at 10:34

2 Answers 2

42

You should always run untrusted code in a separate process, which is exactly what the sandbox module does. A simple reason is that vm.runInNewContext('while(true){}', {}) will freeze node.

It starts by spawning a separate process, which will later send the result serialized to JSON on its stdout. The parent process continues executing regardless of what the child does and can trigger a timeout.

The untrusted code is then wrapped in a closure with strict mode (in regular JavaScript, you can use arguments.callee.caller to access data outside of your scope). Finally, a very limited global object is passed to prevent access to node's API. The untrusted code can only do basic computation and has no access to files or sockets.

While you should read sandbox's code as an inspiration, I wouldn't recommend using it as is:

  • The code is getting old and hasn't been updated for 7 months.
  • The Child Process module in node already provides most of the features you need, especially child_process.fork().
  • The IPC channel provided by child_process.fork probably has better performances.

For increased security, you could also consider using setuid-sandbox. It's the code used by Google Chrome to prevent tab processes from accessing the file system. You would have to make a native module, but this example seems straightforward.

Sign up to request clarification or add additional context in comments.

3 Comments

The methods in the vm module now support a timeout parameter which lets you safely execute while(true) {}. It obviously doesn't address the security concerns, but it does address endless loops.
@AndrewPaprocki Can you link to the docs where timeout is shown?
This answer is very good. Still, I want to point to another similar question (more recent) which may be helpful to people with the same problem: stackoverflow.com/questions/17513212/…
16

There is a newer module on github called vm2 that addresses some of these concerns, especially in Node.JS applications. Maybe that will help some others find it, as I have just done.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.