MCP server WebAssembly security: WASI capabilities model and sandboxed tool execution
WebAssembly (Wasm) combined with the WebAssembly System Interface (WASI) provides a hardware-enforced sandbox for running MCP tool handlers in complete isolation. Unlike container-based isolation (which shares a kernel) or process isolation (which shares a filesystem namespace), Wasm modules have no capabilities by default — filesystem access, network calls, environment variable reads, and clock access must each be explicitly granted as WASI capabilities before the module can use them.
Why Wasm sandboxing for MCP tool execution
MCP tool handlers are arbitrary code that runs in your server process. Without isolation, a bug or vulnerability in a tool handler — or a malicious tool that was installed via a supply chain compromise — can access everything the server process can access: other tools' data, the filesystem, network endpoints, environment variables containing API keys.
Wasm sandboxing moves tool handlers from "runs with full process privileges" to "runs with only the capabilities it explicitly requested and that the server host approved." This maps perfectly to the principle of least privilege and makes the security properties of each tool auditable at load time: before executing a Wasm module, you can inspect exactly which WASI capabilities it imports.
The WASI capabilities model
WASI capabilities are file descriptors and handles that the host process grants to the Wasm module. The module cannot acquire capabilities it wasn't given. The key WASI capability categories:
- Filesystem access (
wasi_filesystem): The host grants the module access to specific directory handles. The module can only read/write within those directories — no path traversal escapes to parent directories because the capability is a directory handle, not a path string. - Network access (
wasi_sockets): In WASI Preview 2, network access requires an explicit capability. A tool module with no socket capability cannot make any network connections — SSRF is impossible by construction. - Environment variables (
wasi_clienvironment): The host explicitly lists which environment variables the module can read. A tool that doesn't need credentials can be given zero environment variables — it can't accessAWS_SECRET_ACCESS_KEYeven if it tries. - Clock and randomness (
wasi_clocks,wasi_random): Even timing information is gated. Modules without clock access cannot perform timing-based side-channel attacks.
Wasm runtime comparison: wasmtime vs. wasmer
wasmtime (Bytecode Alliance): The reference WASI implementation, written in Rust. Uses Cranelift for JIT compilation. Strong security track record, frequent audits, and is the runtime Fastly, Cloudflare, and Fermyon use in production. The wasmtime Rust crate and @bytecodealliance/wasmtime-node npm package provide embedder APIs for running Wasm from Node.js MCP servers.
wasmer: Alternative Wasm runtime with multiple compiler backends (Cranelift, LLVM, Singlepass). LLVM backend produces fastest native code; Singlepass is suitable for running untrusted modules quickly (no JIT for reduced attack surface). Wasmer's wasmer-js package runs in Node.js.
For MCP server tool isolation, wasmtime is the recommended choice due to its security focus and the Bytecode Alliance's ongoing investment in WASI security specifications. Use wasmer's Singlepass backend if you need to execute untrusted Wasm from user-submitted plugins where compile-time security matters.
Memory limits and CPU constraints
Wasm linear memory is bounded: the module declares its maximum memory pages (each 64KB) at compile time, and the host can enforce an additional ceiling. Set per-tool memory limits based on the tool's expected data volume — a tool that reads a config file doesn't need 4GB of memory. Use wasmtime's StoreLimits or the epoch-based fuel mechanism to enforce CPU time limits, preventing a tool from running an infinite loop and starving the server.
Capability inspection at install time
Before loading a Wasm MCP tool module, inspect its imports to see exactly which WASI capabilities it requests. A tool module that imports wasi_sockets::tcp_create_socket is requesting network access — you can make an explicit, auditable decision about whether to grant it. SkillAudit's supply chain analysis reads Wasm module imports and flags capability requests that are broader than the tool's stated purpose (e.g., a "read PDF" tool that requests socket access is suspicious).
What SkillAudit checks for Wasm-based MCP tools
For MCP servers that use Wasm for tool execution, SkillAudit checks:
- Wasm module imports analyzed for capability requests exceeding declared purpose
- Memory limits set below reasonable maximums (unbounded memory = resource exhaustion risk)
- CPU/fuel limits configured to prevent runaway execution
- Network socket capabilities not granted to tools with no stated networking purpose
- Filesystem capabilities restricted to tool-specific directories, not root or home
- Environment variable allowlist configured (not "inherit all host env vars")