Skip to content
Runtime

WebAssembly vs microVM is Wasm safe enough for LLM code?

Runtime Cloud (withruntime.com) runs a full Linux machine. WebAssembly isolates a module.

Which should you use, WebAssembly or a microVM?

It depends on who writes the code and what it expects. For code an agent or model wrote, which expects a shell, packages, subprocesses and the network, Runtime gives it a Firecracker microVM. Pick WebAssembly for plugins, user-defined functions and edge handlers you compile yourself, with a narrow interface where the host grants every capability.

How WebAssembly isolates code

WebAssembly is a bytecode format run by a runtime such as Wasmtime. The specification's security page says "each WebAssembly module executes within a sandboxed environment separated from the host runtime using fault isolation techniques." A module has its own linear memory, and accesses to it are bounds-checked. Calls go only to declared functions, and indirect calls are type-checked. A module can reach the outside world only through the functions its host chose to import.

WASI extends that to system resources. In its words, a module "starts with no ambient authority and can only do what the host explicitly grants." A host that grants no directory gives the module no files. One that grants no sockets gives it no network.

Wasmtime adds defence in depth on top: a 2 GB guard region before each linear memory, memory zeroed after an instance ends where it can be, Spectre mitigations on bounds checks, and continuous fuzzing through Google's OSS-Fuzz.

How a microVM isolates code

A microVM runs a guest Linux kernel under a hypervisor. Firecracker, which Runtime uses, asks the host's KVM for a virtual machine. It gives the guest what its site counts as "only 5 emulated devices". The code inside can do anything Linux allows, root included, because the boundary is the virtual machine itself. Firecracker's design document starts from the worst case: "all vCPU threads are considered to be running malicious code as soon as they have been started."

Side by side

WebAssembly (Wasmtime with WASI) MicroVM (Firecracker)
Unit of isolation One module in a runtime, often inside your own process A virtual machine with its own Linux kernel
Boundary Software fault isolation, validated by the runtime Hardware virtualization through KVM
What the code can call Only functions the host imports; WASI grants per capability Any Linux system call, answered by the guest kernel
What reaches the host The runtime's code and every host function you expose 5 emulated devices, in the project's count
Languages Anything compiled to Wasm; Python needs a Wasm build Any Linux program, unchanged
Packages Must be built for Wasm; native extensions need cross-compile apt, pip, npm as on any Linux machine
Processes and threads Pyodide, CPython's Wasm port, cannot start either Normal Linux processes and threads
Start time No single figure published by Wasmtime Up to 125 ms to guest init, in Firecracker's specification
Gaps the spec names Code reuse, TOCTOU races, timing side channels The guest kernel is the code's own; the host's is not shared

Is WebAssembly safe enough for LLM code?

For a small, pure function compiled to Wasm and given no imports, the sandbox is strong and cheap. The question is what the code needs, because each import is a hole you cut on purpose.

Model-written code rarely stays pure. It opens files, installs packages, calls APIs and starts processes. Each of those becomes a host function that your Wasm host implements and has to get exactly right. The specification says "other classes of bugs are not obviated by the semantics of WebAssembly": code reuse attacks against indirect calls, time-of-check to time-of-use races, and side channels such as timing attacks.

The host layer is where real bugs land. On 20 August 2026 Wasmtime published a High-severity advisory, GHSA-vqjp-4c8c-hfgg, "Filesystem sandbox escape when paths or symlinks contain trailing slashes", in its WASI implementation. That was a flaw in the capability layer, not in Wasm itself. That is the point: the more of the operating system you expose, the more of an operating system you are writing.

A microVM moves that work into a real Linux kernel that the code owns. If the code breaks the guest kernel, it has broken only its own disposable machine.

Can WebAssembly run Python or pip install?

Only in a Wasm build. Pyodide ports CPython to WebAssembly. Its package installer takes pure-Python wheels and packages cross-compiled for Pyodide, and threading, multiprocessing and subprocess raise RuntimeError. Pyodide vs a server sandbox covers the limits in full. A microVM runs the Python on the machine, so any wheel on PyPI installs.

When each fits

  • Pick WebAssembly for plugins and user-defined functions inside your own service, edge handlers, and code you compile yourself with a narrow, known interface, where the host decides every capability.
  • Pick a microVM for code an agent or model wrote in an ordinary language, which expects a shell, a package manager, a filesystem, subprocesses and the network, and which you cannot review before it runs.

Runtime Cloud

Runtime gives model-written code a whole Firecracker microVM, so it runs as written: Python, Node.js, shell, pip install, subprocesses.

Runtime gives each sandbox its own Firecracker microVM with Ubuntu 24.04, Python 3.12, Node.js 24, Bun, git and gcc. The controls a Wasm host would implement live on the Runtime host, outside the guest, so root inside cannot change them (security):

  • Network: off, or narrowed to named hosts. Private addresses are always refused (turn off sandbox internet).
  • Time: commands time out, and the sandbox stops at the time limit you set.
  • Money: maxTotalCostMicros stops a sandbox once it has cost that much in all.
TypeScriptimport { Sandbox } from "withruntime";const code =  "import subprocess; print(subprocess.run(['uname', '-r'], capture_output=True, text=True).stdout)";await using sbx = await Sandbox.create({  network: { internet: false },  timeoutSeconds: 300,  onLeaseEnd: "stop",});await sbx.files.write("/workspace/answer.py", code);const run = await sbx.exec(["python3", "answer.py"], { timeoutMs: 30_000 });console.log(run.exitCode, run.stdout);
Pythonfrom withruntime import Sandboxcode = "import subprocess; print(subprocess.run(['uname', '-r'], capture_output=True, text=True).stdout)"with Sandbox.create(    network={"internet": False},    timeout_seconds=300,    on_lease_end="stop",) as sbx:    sbx.files.write("/workspace/answer.py", code)    run = sbx.exec(["python3", "answer.py"], timeout_ms=30_000)    print(run.exit_code, run.stdout)

The model's subprocess call works, because the sandbox is a real Linux machine. The network stays off whatever the code tries.

More: microVM vs container, run untrusted LLM code, what is a microVM?, unikernel vs microVM.

Try it free: 100 free hours of a 1 GB machine in the first 30 days, no card:

Terminalnpx withruntime sandboxes run -- python3 -c 'import subprocess; print(subprocess.run(["id"]))'

Sign in with npx withruntime login and try it on the free usage. Code on another sandbox today moves with the migration guide.

Sources

Checked 26 October 2026.

Facts on this page were checked on 26 October 2026.

Keep comparing.

100 free hoursin your first 30 days.

of a 1 GB machine

  • No credit card
  • Four sandboxes at once, 2 vCPU and 4 GiB each
  • Then prepaid credit from $10, no plan fee
Start free, no card
Start free, no card