Hacker News new | ask | show | jobs
by simonw 989 days ago
The thing I want to achieve with WebAssembly is still proving a lot harder than I had anticipated.

I want to be able to take strings of untrusted code provided by users and execute them in a safe sandbox.

I have all sorts of things I want this for - think custom templates for a web application, custom workflow automation scripts (Zapier-style), running transformations against JSON data.

When you're dealing with untrusted code you need a really robust sandbox. WebAssembly really should be that sandbox.

I'd like to support Python, JavaScript and maybe other languages too. I want to take a user-provided string of code in one of those languages and execute that in a sandbox with a strict limit on both memory usage and time taken (so I can't be crashed by a "while True" loop). If memory or time limit are exceeded, I want to get an exception which I can catch and return an error message to the user.

I've been exploring options for this for quite a while now. The furthest I've got was running Python in wasmtime: https://til.simonwillison.net/webassembly/python-in-a-wasm-s... and running Pyodide inside of Deno: https://til.simonwillison.net/deno/pyodide-sandbox

Surprisingly I've not found a good pattern for running a JavaScript interpreter in a WASM sandbox yet. https://github.com/justjake/quickjs-emscripten looks promising but I've not found the right recipe to call it from server-side Python or Deno yet.

Can Extism help with this? I'm confident I'm not the only person who's looking for a solution here!

10 comments

The problem you want solved, perfect sandboxing for untrusted code, is only just THE single most important problem in operating system security. If you can solve that then you have the basis of a perfectly secure, unhackable operating system. Anybody claiming to solve that problem at speed in any other software domain can trivially use those same techniques to create a perfectly secure operating system runtime.

So, you have to wonder to yourself, if they can do that why do they not just go and write a unhackable operating system. It is only like one of the single greatest problems of all the commonly used commercial operating systems in what is viewed as one of the most hardcore of software disciplines where solving it would instantly establish you as a supreme software guru. Basically, if you can solve that problem you should make and advertise a unhackable operating system; anything else is selling gold bricks as ballast.

To channel Theo de Raadt of OpenBSD: You are absolutely deluded, if not stupid, if you think that a worldwide collection of software engineers who can't write operating systems or applications without security holes, and then turn around and suddenly write browser sandboxes (originally virtualization layers) without security holes.

The browser has offered this kind of sandboxing for JavaScript for decades at this point.

The reason I'm so excited about WebAssembly for this is that it's not even new technology: it's been supported by widely deployed browsers since 2017.

Browser sandbox escapes from untrusted JavaScript are discovered and exploited regularly. JavaScript is much more constrained than the full force of a low level language like WebAssembly, and they can not even get the JavaScript sandbox safe to run truly untrusted or malicious code. Why would something harder to do work when they can not even do the easier thing?

Unless you are just talking about something meant to handle accidentally, not intentionally malicious code. Then sure, it is probably be okay for that. But if you are actually worried about malicious code then, no, browsers (and commercial operating systems) do not provide that. And anybody suggesting they can do that is almost certainly lying unless they also claim to have developed a unhackable operating system/virtual machine as well.

I know that it's hard, but I'm not ready to agree that this isn't worth seeking answers to.

AWS run untrusted code on Lambda all the time.

Browsers seem to be handling this pretty well in the face of the most untrustworthy computing environment our species has yet developed. Zero days in browsers are big news, and don't happen very often.

If you can sandbox arbitrary malicious code, then you can make a unhackable operating system/runtime. Such a feat is frequently viewed as literally impossible in many software circles and would constitute a extraordinary claim that demands impeccable, extraordinary evidence to support it such as, minimally, mathematical proofs of the entire code base. Nothing less should overcome the sheer ideological inertia behind the common-sense view that everything is easily hacked as has been continuously demonstrated on basically everybody all the time.

So, unless you want to claim Amazon has invented a unhackable operating system to run AWS, has the mathematical proofs of correctness to support such a extraordinary claim, and has just not bothered to tell anyone, claiming AWS can actually securely run untrusted code is pure unsupported bluster. In fact, I bet exactly zero people at Amazon would back up such a claim if pressed, and if even the people doing it think it is impossible then there is no way they are actually doing it. The same goes for browsers.

As to zero days in browsers being big news, they are really not. Zerodium only pays 500 K$ for a Chrome RCE+LPE [1]. That is pocket change. Ransomware attacks ask for millions of dollars per attack these days. They can literally afford to burn multiple Chrome RCEs per attack (if needed) and still come out profitable. The cost of sandbox escape needs to be somewhere around 20-100x higher for it to be viewed as "secure" against the common threats seen every day.

[1] https://zerodium.com/program.html

> AWS run untrusted code on Lambda all the time.

AWS uses virtualization (Firecracker) to provide isolation for Lambda.

WebAssembly vs browser/javascript isolation is a little like virtualization vs operating system level isolation. WebAssembly and virtualization offer far smaller attack surfaces which mean they are far more likely to remain secure in the long term.

Browsers and operating systems are highly complex abstractions and they only remain secure (if you keep them patched) through the large ongoing investment in them.

Webassembly is far more constrained in the browser than Javascript. Exploits are flaws in the implementation that can be fixed, but what is being asked for is an environment that has fewer privileges by design.
Fuchsia solves that.
Yeah, you are going to need to support a claim of solving the biggest problem in operating system security with more than a random assertion.

How about you start by finding a quote by any member of the development team who is willing to support the claim that Fuchsia establishes unhackable separation/sandboxes? If nobody making the software is willing to say that then we can be sure that they did not achieve it.

You can then follow it up by pointing to a mathematical proof that the code enforces separation kernel security properties where the proof has been verified by a competent third party. I will not demand you present or link the proof, all you need to show is that one exists and a credible party assents.

Only then do you have the bare minimum of evidence needed to support a assertion like that.

To run a JavaScript interpreter (spidermonkey, in this case) in Wasm, as well as running that same wasm in a JS engine, you want to look at `jco` https://github.com/bytecodealliance/jco

The component model tooling is getting very close to maturity and will solve many of these problems.

That's really useful. This page in particular: https://github.com/bytecodealliance/jco/blob/main/EXAMPLE.md

Being able to run "jco wit cowsay.wasm" to see what interfaces that .wasm file provides solves a problem I've run into a bunch of times in the past.

you should also check out modsurfer[0]

"modsurfer generate -p cowsay.wasm -o mod.yaml"

Especially for non-component core modules that wont have wit definitions

[0]: https://github.com/dylibso/modsurfer

Hey Simon, I've done some similar experimentation using Extism to sandbox LLM generated code. This uses our JavaScript PDK (which uses quickjs) and can be embedded in any host language we support https://extism.org/blog/sandboxing-llm-generated-code

I'm also working on a Python-PDK right now and hope to have a beta ready in the next month. That would allow us to do something similar with python.

Sandboxing code generated by LLMs is another of my use-cases for this, that's a fantastic link, thanks!
I think I referenced one of your blog post in that article too. So thank you!
As a robust sandbox, have you considered using a micro-VM? Firecracker [1] comes to mind, the VM behind AWS Lambda. It's designed to be lightweight to launch, suitable for running ephemeral code.

While I agree that it'd be nice to be able to use WASM for this purpose, it seems like a microVM might provide a more convenient interface: you can "just" run any existing programming language inside it (without needing any specific support for e.g. WASM). Indeed, you could run multiple processes built with different programming languages together and allow them to communicate in standard ways.

Additionally, VMs offer a number of advantage from a security perspective. Hypervisor VMs take advantage of hardware support, and their surface area is arguably well-hardened and smaller than alternatives (hence why VMs are used for cloud computing).

> I've not found a good pattern for running a JavaScript interpreter in a WASM sandbox yet

Is there a good reason to do this? I thought WASM typically used the V8 JavaScript interpreter as its sandbox and to execute code. If you could launch WASM, couldn't you equivalently launch an instance of V8 with the JavaScript code running inside directly? I do think this is a good question, and it raises further questions like: what if I want to run JavaScript and WASM side-by-side, so that they can communicate with each other and/or with native code.

[1] https://firecracker-microvm.github.io/

Firecracker is a fine technology, but serverless companies have started taking advantage Wasm's faster start-up and invocation times for use cases of running Wasm on the server (https://www.youtube.com/watch?v=yqgCxhPAao0). The deny by default security policy makes Wasm a popular choice to run code in isolation, particularly for maximizing hardware resources in the multi-tenant environments these serverless companies operate.

> Is there a good reason to do this?

One use case to run JS inside a Wasm VM is Shopify Functions. Shopify allows their customers to customize things like checkout flow by writing code compiled to Wasm which gets executed during the checkout process. They want their customers to be able to write JS as well as other languages. https://github.com/Shopify/function-runner

> I thought WASM typically used the V8 JavaScript interpreter as its sandbox and to execute code.

V8 is popular for running Wasm on the web and for some serverless companies, but there are a bunch of serverless, blockchain, and iot projects that use other Wasm runtimes (Wasmtime, WAMR, WasmEdge, and Wasmer to name a few) - https://github.com/appcypher/awesome-wasm-runtimes

I'm working on this problem as well and would be happy to sling you some thoughts and notes. Check my website https://runno.dev and send an email to the address on that website!
I'm building something that solves this exact problem, and I'll have an alpha version ready soon. Drop me a mail at marc@ my username .net, if you're interested. I'd also really like to have a chat about your use cases if you're up for it.

Cheers, Marc

I created https://github.com/dicej/component-sandbox-demo when you asked about this on the Bytecode Alliance Zulip. Curious if you have any feedback on it.
Oh wow, I hadn't checked in on this. Looks like a much more complete method than the one I explored in https://til.simonwillison.net/webassembly/python-in-a-wasm-s...

Thanks! I'll give this a shot.

>When you're dealing with untrusted code you need a really robust sandbox. WebAssembly really should be that sandbox.

We shouldn't have to trust any code. WASM is a stepping stone out of the insanity that is ambient authority.

As another reply says, there's no such thing as perfect sandboxing unfortunately, especially not with the string of CPU side channels that have been uncovered, and continue to be revealed.
> I want to be able to take strings of untrusted code provided by users and execute them in a safe sandbox.

Isn't this the entire pitch of the browser as an app platform rather than a document viewer? Why target it if it's not sandboxed?