July 7th, 2024

Execute JavaScript in a WebAssembly QuickJS Sandbox

QuickJS is a secure JavaScript execution tool in a WebAssembly sandbox. It includes security features, file system access, custom node modules, a fetch client, and a test runner. Find detailed documentation and examples in the repository. Users can seek further assistance for inquiries.

Read original articleLink Icon
Execute JavaScript in a WebAssembly QuickJS Sandbox

QuickJS is a JavaScript execution tool that operates securely within a WebAssembly sandbox. It offers various features like security enhancements, file system mounting, custom node modules, a fetch client, and a test runner. Detailed documentation can be accessed at the provided link, along with practical examples available in the repository. For additional information or inquiries regarding QuickJS, users are encouraged to seek further assistance.

Related

What Happens When You Put a Database in the Browser?

What Happens When You Put a Database in the Browser?

WebAssembly (Wasm) enhances browser capabilities, enabling high-performance apps like DuckDB for ad-hoc queries and Python environments. DuckDB Wasm boosts performance in interfaces like lakeFS, Evidence, and Count. MotherDuck enables local querying, emphasizing efficient data processing.

Show HN: Synapse – TypeScript Toolchain for Cloud Apps

Show HN: Synapse – TypeScript Toolchain for Cloud Apps

Synapse is a full-stack TypeScript toolchain with resource-driven programming, cloud-agnostic libraries, and fine-grained permissions. It includes a TypeScript compiler, fast package manager, and testing framework for local or AWS deployment. Installation instructions vary by OS. Leveraging TypeScript, esbuild, Node.js, Terraform, and AWS SDK. Detailed documentation on GitHub covers Custom Resources, Environments, Packages, and Tests, with a Quick Start guide available.

Apple Disables WebKit's JIT in Lockdown Mode, & BrowserEngineKit Is Restricted

Apple Disables WebKit's JIT in Lockdown Mode, & BrowserEngineKit Is Restricted

Apple has disabled WebKit's JIT in Lockdown Mode for enhanced security, aligning with EU's DMA. BrowserEngineKit enables secure JIT compilation, balancing performance and safety, requiring authorized developers for alternative browser engines.

Denotational Semantics and a Fast Interpreter for jq (2023)

Denotational Semantics and a Fast Interpreter for jq (2023)

The paper introduces denotational semantics for the jq programming language, addressing the lack of a formal specification. A new interpreter, jaq, outperforms jq on benchmarks, submitted to OOPSLA 2023.

JavaScript Visualized – Event Loop, Web APIs, (Micro)Task Queue [video]

JavaScript Visualized – Event Loop, Web APIs, (Micro)Task Queue [video]

The event loop in JavaScript is crucial for managing asynchronous tasks efficiently. It includes the call stack, web APIs, task queue, and microtask queue, enabling non-blocking operations. For more details, feel free to inquire.

Link Icon 23 comments
By @jitl - 5 months
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

By @AlexErrant - 5 months
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_.

By @frabjoused - 5 months
Coincidentally I was trying out quickjs last week and ultimately ended up settling on isolated-vm instead as both met our security contrasts, however isolated-vm ended up being far more performant in terms of setup, teardown and eval execution overhead.
By @emurlin - 5 months
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

By @FpUser - 5 months
CPU got too fast so let's run interpreter inside interpreter.
By @jitl - 5 months
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.
By @leohart - 5 months
This is awesome. With this, I would be able to run JS code that my user provides. I have been looking for a way to bundle my user Typescript code using a bundler in a sandbox environment. Any recommendation on ways to run a bundler (webpack/...) in QuickJS?
By @brigadier132 - 5 months
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.
By @aitchnyu - 5 months
In a previous job, I got way too many "segmentation faults" from Quickjs-emscripten and silent errors and project was put on hold. I will probably use an engine which works correctly on more programs and has an officially blessed wasm bundle if I had to do it again.
By @remram - 5 months
I thought you could safely sandbox code via an iframe, though I'm not certain. Of course using your own interpreter might allow for more features, like tighter timeouts, custom APIs, etc.
By @EGreg - 5 months
How can I make sure the iframe cannot make any requests to any servers, including WebSockets?

Also what happens if the code has infinite loops? Is there an ability to pause execution? That woukd be helpful

By @anonymousd3vil - 5 months
so we come to a full circle
By @WatchDog - 5 months
I had started working on something very similar to this, a higher level wrapper for quickjs-emscripten.

quickjs-emscripten is great, but it's API is deliberately very close to quickjs's C API. It can be quite difficult to use directly, and implementing support for loading libraries is non-trivial, especially if any of those libraries depend on certain nodejs or browser APIs.

Implementing support for `require()` is tricky, because it's a blocking API, so doing any async IO to fetch module code is not possible unless you either:

- Use the asyncifyed version of quickjs-emscripten(slower and more difficult to use) - Use blocking IO to load modules(not ideal). - Pre-load all module files into an in-memory filesystem(which is what is sounds like this lib is doing).

I haven't looked much into how the quickjs-emscripten-sync library works exactly, but automatic syncronization of host and guest functions, seems like it could be a big attack surface, and I worry that it might be possible to escape the sandbox with it somehow.

By @waldrews - 5 months
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...
By @cal85 - 5 months
Does this support running in a browser? I can’t find any mention of supported environments in the docs.
By @bluelightning2k - 5 months
Oh very nice! Guessing there isn't support for node modules but still very cool.
By @djaouen - 5 months
If you’re on wasm, why not just use Elixir and be done with it?
By @devwastaken - 5 months
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.
By @revskill - 5 months
Does it support browser ?
By @owenpalmer - 5 months
This is an xkcd waiting to happen
By @jojobas - 5 months
I thought the whole purpose of WebAssembly was not to execute any JavaScript.