This repository has been archived by the owner. It is now read-only.

leaking references inside new contexts #1469

bmeck opened this Issue Aug 7, 2011 · 8 comments


None yet
5 participants

bmeck commented Aug 7, 2011

vm.runIn* can be leaked the require function if they are passed a function and / or an object that can be called (via type-coersion, cached value, prototype, or otherwise) from inside another module.

example abuse node vm.js abuse.js:




function caller() {
  var visited = [];
  var fn = caller.caller;
  while(fn && visited.indexOf(fn) === -1) {
    try {
      fn = fn.caller;
    catch(e) {break;}

on simple inspection adding "use strict" to vm.js appears to work, however if we add a little tweak to abuse.js:

console.toString.constructor('console','console.dir((function(){return this})())')(console)

We see that we have a privileged Function constructor and access to some globals that we do not want to be leaked.


  • We should not have these globals
  • All module wrappers should be done in strict mode to prevent getting the require function from their arguments from calls being done inside them.

felixge commented Aug 8, 2011

I had a look, but I think I'm -1 on your proposals.

  • I don't think we'll remove the current globals
  • Adding 'use strict' to the source can be done in userland, node itself should not enforce it (unless we enforce it everywhere)

That being said, the second "jailbreak" is very nasty indeed. I'm not quite sure how to avoid it if you want to inject direct references to objects from your main context into your sandbox.


bmeck commented Aug 8, 2011

'use strict' in modules is not doable in userland since any leaked native modules can get the require function used in them if a function is called from a scope in the native module. If the wrapper for modules is able to be in strict mode but the actual code executed in privileged mode that would be ideal. Perhaps there is a way to wrap the module execution in a closure?

felixge commented Aug 8, 2011

'use strict' in modules is not doable in userland since any leaked native modules

You must not leak a native module to the sandbox I think. You can use process.nextTick to drop the stack of the initial module execution.

Perhaps there is a way to wrap the module execution in a closure?

The module execution is wrapped in a closure already.

thejh commented Sep 4, 2011

I have a proposal for the caller thing: I think that you can't escape recursion. Therefore, this should work:

function runInNewContext(code, sandbox) {
  _runInNewContext(code, sandbox, true);

function _runInNewContext(code, sandbox, recurse) {
  if (recurse) return _runInNewContext(code, sandbox);

thejh commented Sep 13, 2011

About the .constructor thing: I think we should prepend a trusted deep-copy snippet to the executed code that replaces the global objects members with deep clones where the clone of a function is a closure wrapping it. All interaction would then have to work using those wrapped functions.

Also, the global object needs all its inherited members to be set to null or so:

> var g = {}
> function run(code){return vm.runInNewContext(code, g)}
> run("__defineGetter__")
[Function: __defineGetter__]
> g.__defineGetter__ = null
> run("__defineGetter__")

bmeck commented Jan 27, 2012

Use the 'sandbox' npm module

@bmeck bmeck closed this Jan 27, 2012

It's not really clear what happened to this. Has this vulnerability been resolved? sandbox npm module doesn't let you expose certain functions safely either, afaict.


bnoordhuis commented Jun 25, 2013

It's resolved in the sense that the vm module doesn't pretend to be an environment for executing untrusted code safely. The vm module documentation is rather explicit on that subject.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.