[HN Gopher] Show HN: Execute JavaScript in a WebAssembly QuickJS...
       ___________________________________________________________________
        
       Show HN: Execute JavaScript in a WebAssembly QuickJS sandbox
        
       This TypeScript package allows you to safely execute JavaScript
       code within a WebAssembly sandbox using the QuickJS engine. Perfect
       for isolating and running untrusted code securely, it leverages the
       lightweight and fast QuickJS engine compiled to WebAssembly,
       providing a robust environment for code execution.  Features  -
       *Security*: Run untrusted JavaScript code in a safe, isolated
       environment.  - *File System*: Can mount a virtual file system  -
       *Custom Node Modules*: Custom node modules are mountable  - *Fetch
       Client*: Can provide a fetch client to make http(s) calls  - *Test-
       Runner*: Includes a test runner and chai based `expect`  -
       *Performance*: Benefit from the lightweight and efficient QuickJS
       engine.  - *Versatility*: Easily integrate with existing TypeScript
       projects.  - *Simplicity*: User-friendly API for executing and
       managing JavaScript code in the sandbox.
        
       Author : sebastianwessel
       Score  : 129 points
       Date   : 2024-07-07 11:37 UTC (11 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | bluelightning2k wrote:
       | Oh very nice! Guessing there isn't support for node modules but
       | still very cool.
        
       | brigadier132 wrote:
       | Very cool. Since this is compiled to wasm can this run in the
       | browser? It would be interesting if it could and still make fetch
       | requests without attaching cookies to the request.
        
       | revskill wrote:
       | Does it support browser ?
        
         | dualogy wrote:
         | Pick one of the wasm runtimes written in JS listed at
         | https://github.com/appcypher/awesome-wasm-runtimes and find out
         | =)
        
       | jojobas wrote:
       | I thought the whole purpose of WebAssembly was _not_ to execute
       | any JavaScript.
        
         | mirekrusin wrote:
         | Too late, he didn't know.
        
         | brigadier132 wrote:
         | Well you'd be mistaken. The point of WebAssembly is to run any
         | language that compiles to WebAssembly in a secure sandbox.
        
         | anon115 wrote:
         | moew meoew moewm meow moew meow XDD the point of wasm is to
         | play video games on the browser.
        
       | jitl wrote:
       | Hi, I'm the author of the underlying quickjs-emscripten runtime
       | library. I like your ergonomic kind of "standard library" for
       | quickjs-emscripten :)
       | 
       | Did you try running in the browser or with a bundler? I think
       | accepting the variant name as a string you pass to
       | import(variantName) dynamically may not play well with Webpack et
       | al.
       | 
       | EDIT: SECURITY WARNING: this library exposes the ability for the
       | guest (untrusted) code to `fetch` with the same cookies as the
       | host `fetch` function. You must not run untrusted code if
       | enabling `fetch`. Library should come with a big blinking warning
       | about what is safe and unsafe to enable when running untrusted
       | code. It's not a "sandbox" if the sandboxed code can call
       | arbitrary HTTP APIs authenticated as the host context!
       | 
       | The reason quickjs-emscripten is low-level and avoids magic is so
       | I can confidently claim that the APIs it does provide _are_
       | secure. I generally reject feature requests for magical
       | serialization or easy network /filesystem access because that
       | kind of code is a rich area for security mistakes. When you run
       | untrusted code, you should carefully audit the sandbox itself,
       | but also audit all the code you write to expose APIs to the
       | sandbox.
       | 
       | In this case a comment from an other HN user asking about Fetch
       | cookies tipped me off to the potential security issue.
       | 
       | More reading:
       | 
       | Figma blog posts on plugin sandbox security:
       | 
       | - https://www.figma.com/blog/how-we-built-the-figma-plugin-sys...
       | 
       | - https://www.figma.com/blog/an-update-on-plugin-security/
       | 
       | Quickjs-emscripten README: https://github.com/justjake/quickjs-
       | emscripten
        
       | jitl wrote:
       | i wouldn't say "performance" as an advantage of running JS in
       | QuickJS. QuickJS isn't competitive at all with the host JS VM,
       | although I guess it's faster than older C interpreters, or an
       | interpreter implemented in JavaScript.
        
         | math_dandy wrote:
         | I suppose you get performance benefits if the the time it takes
         | to start up a nodejs process dominates the execution time of
         | the script. This is probably the case for a decent proportion
         | of "serverless function" type scripts.
        
           | jitl wrote:
           | This library expects to run inside a Javascript runtime like
           | NodeJS, so you're always going to pay for the enclosing
           | Javascript runtime to start.
        
             | ijustlovemath wrote:
             | Not true, QuickJS works completely standalone. I've used it
             | to compile NodeJS libraries into standalone libraries that
             | other C libraries can call, even on a system without a
             | NodeJS install.
        
       | anonymousd3vil wrote:
       | so we come to a full circle
        
         | TheRealPomax wrote:
         | Spiral. Not circle. Having something run in itself is as old as
         | the need to safely run something in order to see if it's going
         | to blow up or not, though. If people aren't trying to write
         | things so your general use programming environment can
         | virtualize itself, it's basically not used seriously enough
         | yet.
        
         | degurechaff wrote:
         | now we just need wasm intepreter in js. so we can run this
         | package to run javascript to run wasm intepreter and so on..
        
       | emurlin wrote:
       | Interesting approach! As an author of another JS sandbox
       | library[1] that uses workers for isolation plus some JS
       | environment sanitisation techniques, I think that interpreting JS
       | (so, JS-in-JS, or as in this case, JS-in-WASM) gives you the
       | highest level of isolation, and also doesn't directly expose you
       | to bugs in the host JS virtual machine itself. Since you're
       | targeting Node, this is perhaps even more important because (some
       | newer developments notwithstanding) Node.js doesn't really seem
       | to have been designed with isolation and sandboxing in mind
       | (unlike, say, Deno).
       | 
       | From the API, I don't see if `createRuntime` allows you to define
       | calls to the host environment (other than for `fetch`). This
       | would be quite a useful feature, especially because you could use
       | it to restrict communication with the outside world in a
       | controlled way, without it being an all-or-nothing proposition.
       | 
       | Likewise, it doesn't seem to support the browser (at least,
       | running a quick check with esm.sh). I think that that could be a
       | useful feature too.
       | 
       | I'll run some tests as I'm curious what the overhead is in this
       | case, but like I said, this sounds like a pretty solid approach.
       | 
       | [1] @exact-realty/lot
        
         | jitl wrote:
         | I'm the author of the underlying quickjs-emscripten library. It
         | supports the browser (specifically tested with ESM.sh), as well
         | as Cloudflare Workers, NodeJS, Deno:
         | https://github.com/justjake/quickjs-emscripten?tab=readme-ov...
         | 
         | It has APIs for exposing host functions, calling guest
         | functions, custom module loaders, etc:
         | https://github.com/justjake/quickjs-emscripten?tab=readme-ov...
         | 
         | API docs for newFunction: https://github.com/justjake/quickjs-
         | emscripten/blob/main/doc...
        
           | brigadier132 wrote:
           | Wow cloudflare workers support is actually super cool. How
           | does it limit memory usage?
        
             | jitl wrote:
             | The quickjs interpreter C code counts the bytes it's
             | allocated, and refuses to allocate more if over the limit.
             | It decrements by the allocation size when freed. This
             | malloc function is used everywhere the interpreter
             | allocates memory:                   static void
             | *js_def_malloc(JSMallocState *s, size_t size)         {
             | void *ptr;                      /* Do not allocate zero
             | bytes: behavior is platform dependent */
             | assert(size != 0);                      if
             | (unlikely(s->malloc_size + size > s->malloc_limit))
             | return NULL;                      ptr = malloc(size);
             | if (!ptr)                 return NULL;
             | s->malloc_count++;             s->malloc_size +=
             | js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
             | return ptr;         }
        
       | jiripospisil wrote:
       | See also https://bytecodealliance.org/articles/javy-hosted-
       | project
        
       | AlexErrant wrote:
       | There are many ways to sandbox Javascript, both serverside and
       | browser-side.
       | 
       | Are there any ways to "sandbox" DOM access? I.e. give untrusted
       | 3rd parties access to a DOM element in a predefined spot? AFAIK
       | the only tech that allows for this is iframes, which are
       | unfortunately heavy and slow. I'm writing an app that can host
       | plugins, and unfortunately, I think giving plugins DOM access
       | means they can now literally do literally _anything_.
        
         | cxr wrote:
         | The closest thing I know of is Allen Wirfs-Brock's jsmirrors
         | prototype, but he never got to speccing out anything for DOM
         | (and never really intended to as far as I know). Just
         | capabilities for JS-the-programming-system.
         | 
         | You could look at jsmirrors for inspiration and take a crack at
         | some sort of "dommirrors" yourself, but it's big undertaking.
         | (There's a roundabout way to go about using jsmirrors as-is to
         | kind of achieve what you want, but it's not ergonomic.)
         | 
         | That being said, giving access to the DOM, even
         | mediated/simulated, is almost certainly not what you really
         | want. Figure out what you _actually_ want to allow the other
         | side to do, and then just give them a capability that lets them
         | do it. (For example, to let them add a button somewhere, you
         | might think you need to give them an anchor point (parent
         | element) where they can insert it and let them use
         | `document.createElement` to make the DOM node that they're
         | going to put there. But you don't actually want that--for them
         | to have access to `document.createElement`, etc. What you want
         | is for them to have an add-button capability. So give them
         | _that_ --go implement `addButton`.)
         | 
         | Moar: <https://news.ycombinator.com/item?id=30703531#30706060>
         | 
         | PS: don't listen to anyone who comes along and says that this
         | is what CSP is for. It's not. (If we're being accurate, even
         | for what CSP really is for, it's poorly designed, user-hostile
         | junk and should never have been implemented or extended as far
         | as it has been.) It's dangerous to depend on it.
        
         | spankalee wrote:
         | Salesforce does this with a combination of web components, with
         | a patched up ShadowRoot so that code with a reference to the
         | shadow root can't walk into the rest of the document, and a
         | secure evaluator function related to SES (Secure EcmaScript) to
         | limit the globals the untrusted script has access too.
         | 
         | The secure evaluator is wild. I think this is the heart of it:
         | https://github.com/Agoric/realms-shim/blob/v1.1.0/src/evalua...
         | 
         | There's also an idea for isolated web components to solve this
         | in the platform:
         | https://github.com/WICG/webcomponents/issues/1002
        
           | cxr wrote:
           | You can also check out the discussion for Figma's earlier
           | work on their plugin system, which is what inspired jitl
           | (above) to create quickjs-emscripten. Previously:
           | 
           |  _How to build a plugin system on the web and also sleep well
           | at night_.  <https://news.ycombinator.com/item?id=20770105>
           | 2019 August 22. 89 comments.
        
           | m1el wrote:
           | Salesforce sandboxing is too easy to escape. Last time I
           | needed to implement some feature for Salesforce, I've
           | encountered 4 different escapes. It was also horrible dev
           | experience.
        
       | waldrews wrote:
       | Yes! Now, we just have to run this inside a browser, which will
       | run inside a container, which will run inside a VM, which will
       | run on an emulation layer...
        
       | djaouen wrote:
       | If you're on wasm, why not just use Elixir and be done with it?
        
       | FpUser wrote:
       | CPU got too fast so let's run interpreter inside interpreter.
        
       | devwastaken wrote:
       | You cannot throw things into wasm and call it safe. It is wholly
       | irresponsible. You need to do the work to ensure it's safe to a
       | theory and in practice.
        
         | brigadier132 wrote:
         | quickjs with wasm can be considered secure before different
         | system apis are introduced
        
       | owenpalmer wrote:
       | This is an xkcd waiting to happen
        
       ___________________________________________________________________
       (page generated 2024-07-07 23:00 UTC)