Vm2: Support for running vm2 in browser

Created on 31 Jul 2017  ·  15Comments  ·  Source: patriksimek/vm2

Branch: https://github.com/patriksimek/vm2/tree/feature-browsers
Library: https://github.com/patriksimek/vm2/blob/feature-browsers/dist/vm2.js

Usage

<script src="vm2.js"></script>
<script>
    const vm = new vm2.VM();
    alert(vm.run('Math.random()'));
</script>

Issues

  • Sandbox can be escaped via window.top.

TODO

  • Remove NodeVM from browser version.
  • Add BrowserVM to browser version with browser related features.
  • Automated browser tests.
feature request help wanted

Most helpful comment

I'm thinking about using web workers to get vm2 working in browsers. I'll give it a shot.

All 15 comments

A somewhat hacky solution could involve AST rewriting to manually wrap each property access. For instance, let x = foo.bar would be rewritten to let x = (x => (x == window.top) ? (some patch here) : x)(foo.bar).

Here is an example of AST rewriting, where function call nodes are wrapped in nodes like this.

The disadvantages to this approach are that you can't easily debug the rewritten code, and that it takes some workarounds to deal with Function, eval and the like.

I think the only way is very heavyweight that is to basically interpret JS yourself, or to replace Functions constructions with a custom implementation (such as inject variable and parse content). This method would be very hard to implement.

Variable deletion is impossible due to variables like document and top that can not be deleted nor overwritten.

@io4, replacing Function, eval and the like at runtime is certainly possible with AST rewriting and it's not terribly difficult either. However, it does incur a heavy performance hit, both at "compile time" since you have to rewrite literally every function call and at runtime since function calls have to go through one layer of indirection.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Please don't close, this is a relevant issue.

I'm thinking about using web workers to get vm2 working in browsers. I'll give it a shot.

Maybe you can put it inside a sandboxed iframe as well. That way if it escapes, it's still restricted to the frame and cannot navigate the top level browsing context.

The status is we can't use web workers because they don't share a memory with the host. I was testing the sandboxed iframe, but no success there either. Without the allow-same-origin option, vm2 doesn't even start. With that option enabled, I can access the top-level window. But I'm not giving up :)

What kind of error did it give you? Did it need to access a variable? Was it missing a library? Any data that could be retrieved by exchanging messages between iframes?

227 is of interest, especially since Realms was mentioned specifically for browser sandboxing.

I did try to fix the access to window with the same trick as realms-shim does.
A implementaition can be found here: https://github.com/XmiliaH/vm2/blob/feature-browsers/lib/vm.js
Disadvantage is that everthing in the vm runs in strict mode.

@patriksimek to get around the window.top issue, could you not observe the object and kill the script (throw and error) if modified/used? So, observe properties and wrap functions

Branch: https://github.com/patriksimek/vm2/tree/feature-browsers
Library: https://github.com/patriksimek/vm2/blob/feature-browsers/dist/vm2.js

Usage

<script src="vm2.js"></script>
<script>
    const vm = new vm2.VM();
    alert(vm.run('Math.random()'));
</script>

Issues

  • Sandbox can be escaped via window.top.

TODO

  • Remove NodeVM from browser version.
  • Add BrowserVM to browser version with browser related features.
  • Automated browser tests.

I don't know of a way to observe window or window.top in a way that allows to throw before something happens.

Hi
I need to import vm2.js as a module into typescript file.
Can someone please help? Thank you

Hi
I need to import vm2.js as a module into typescript file.
Can someone please help? Thank you

Working as a module: added module.exports = vm2; in the end of file.

Was this page helpful?
0 / 5 - 0 ratings