I've been looking into WASM sandboxing for agent tool execution, and while the principle is straightforward, I think the "how" gets glossed over. The core idea is that WebAssembly provides a capability-sealed environment, not just a wall.
A malicious WASM module can't read `/etc/passwd` because it literally has no concept of your host's filesystem. The module operates in a linear memory space that is its entire universe. It can only interact with the outside world through functions you explicitly **import** into it. If you don't import a `readFile` function, it simply doesn't exist from the module's perspective.
Here's a simplistic illustration of the host's responsibility:
```c
// Hypothetical host environment (e.g., in Go or Rust)
// You define what functions the WASM module can call.
wasmtime::Linker::new(&engine)
.func_wrap("host_env", "log", |msg_ptr: i32| {
// Allow logging. That's it.
println!("Module says: {}", read_wasm_string(memory, msg_ptr));
})
// NO file system functions are added here.
// NO network functions are added here.
```
The real security boundary is the **host runtime** (like Wasmtime, Wasmer, or a browser engine). Its job is to faithfully enforce that the WASM code can only call those imported functions and cannot perform arbitrary system calls. The current escape research focuses on:
* Bugs in these runtime implementations (e.g., memory corruption in the compiler/runtime itself).
* Overly permissive host-provided imports (like giving a tool a full `filesystem` capability when it only needs `read_temp_dir`).
* Side-channel attacks, which are harder but becoming a research focus.
So, the isolation is genuine **if** the runtime is secure and you follow the principle of least privilege with imports. It's security theater if you just run a WASM module and blindly give it a `syscall` import that maps directly to host system calls. The strength is in the explicit capability model.
Don't trust the model