WebAssembly was designed with security as a first-class concern. The specification defines a sandboxed execution environment that isolates WebAssembly modules from the host system and from each other. This sandbox is real and meaningful -- it prevents entire categories of attacks that native code is vulnerable to. But the sandbox is not a magic boundary that makes all WebAssembly code safe.
Understanding what the sandbox does and does not protect against is essential for anyone building with WebAssembly, whether in the browser, on the server with WASI, or in edge computing environments.
What the Sandbox Provides
Linear memory isolation. Each WebAssembly module operates on a contiguous block of linear memory that it owns. The module cannot access memory outside this block. It cannot read or write the host's memory, other modules' memory, or the JavaScript heap. This prevents buffer overflow exploits from escaping the module's memory space -- a significant improvement over native code where a buffer overflow can corrupt arbitrary memory.
Control flow integrity. WebAssembly's structured control flow prevents arbitrary jumps. There are no goto statements, no computed jumps to arbitrary addresses. Function calls go through an indirect call table that is bounds-checked at runtime. This makes return-oriented programming (ROP) attacks -- a staple of native exploit chains -- fundamentally harder.
Type safety at the instruction level. Every WebAssembly instruction operates on typed values. You cannot reinterpret a float as a pointer or add a string to an integer. The validator rejects modules that violate type constraints before they execute.
No ambient authority. A WebAssembly module starts with no capabilities. It cannot access the file system, network, or any system resource unless the host explicitly provides functions that grant those capabilities. This is a capability-based security model, and it is sound.
What the Sandbox Does Not Provide
Protection against logic bugs. The sandbox prevents memory corruption and unauthorized system access. It does not prevent a WebAssembly module from computing the wrong answer, implementing a flawed cryptographic algorithm, or making an incorrect authorization decision. Business logic vulnerabilities exist regardless of the execution environment.
Protection against timing attacks. WebAssembly provides high-resolution timing through performance.now() access in the browser. This enables timing side-channel attacks, including variants of Spectre. Browser vendors have implemented mitigations (reduced timer resolution, site isolation), but the fundamental risk remains.
Protection against supply chain compromise. The sandbox does not care whether the WebAssembly binary was produced from legitimate or malicious source code. A supply chain attack that replaces a legitimate .wasm file with a malicious one executes the malicious code with full sandbox permissions. The sandbox contains the damage but does not prevent the attack.
Isolation between host-provided capabilities. If the host provides a WebAssembly module with a function that writes files and another function that sends network requests, the module can use both. The sandbox does not enforce policies about which combinations of host capabilities the module uses. That is the host's responsibility.
Browser WebAssembly Security
In the browser, WebAssembly runs within the same security context as JavaScript. A WebAssembly module loaded from example.com is subject to the same-origin policy, CSP restrictions, and permission models that apply to JavaScript from example.com.
The Content Security Policy script-src directive controls WebAssembly loading. If your CSP blocks inline scripts, it also blocks WebAssembly.compile() and WebAssembly.instantiate() with raw bytes unless you include 'wasm-unsafe-eval' in your CSP. This CSP directive was specifically introduced to allow WebAssembly compilation while still blocking JavaScript eval().
WebAssembly modules in the browser are subject to the same cross-origin restrictions as scripts. You cannot load a WebAssembly module from a different origin unless that origin sets appropriate CORS headers. This prevents arbitrary .wasm loading from untrusted sources.
Memory is a significant consideration. WebAssembly linear memory is backed by an ArrayBuffer (or SharedArrayBuffer for threads). The maximum memory a module can allocate is bounded by the browser and the system, but a malicious module can allocate and fill memory rapidly, causing denial of service. Browsers do not impose per-module memory limits -- a single WebAssembly module can exhaust available memory.
WASI and Server-Side Security
The WebAssembly System Interface (WASI) extends WebAssembly's capabilities beyond the browser by providing standardized system call interfaces. WASI uses a capability-based security model where the runtime grants specific capabilities (file system access, network access, environment variables) at instantiation time.
WASI's capability model is granular. You can grant a module read access to a specific directory without granting write access. You can grant network access to specific addresses without granting universal network access. This granularity enables the principle of least privilege.
But WASI is still evolving. The preview implementations vary in completeness and security properties across runtimes (Wasmtime, Wasmer, WasmEdge). Some runtimes implement WASI capabilities with more restrictions than others. Test your security assumptions against the specific runtime you deploy on.
Supply Chain Implications
WebAssembly modules are distributed as binary files. Unlike JavaScript, they are not human-readable. You cannot casually inspect a .wasm file to understand what it does. Disassembly tools (wasm2wat, wasm-decompile) exist, but the output is low-level and difficult to audit.
This opacity makes supply chain verification harder. When you include a pre-compiled WebAssembly module from a third party, you are trusting that the binary matches the claimed source code. Reproducible builds for WebAssembly exist (the compilation is deterministic for a given toolchain version and configuration) but are not universally practiced.
The WebAssembly ecosystem currently lacks the package management infrastructure that npm or crates.io provides. WebAssembly modules are often distributed as standalone files, through CDNs, or embedded in JavaScript packages. This fragmented distribution makes centralized vulnerability tracking difficult.
When WebAssembly modules are distributed inside npm packages, they inherit npm's supply chain risks. A compromised npm package can include a malicious .wasm binary alongside legitimate JavaScript code. Standard npm audit tools scan JavaScript but typically do not analyze WebAssembly binaries.
Attack Scenarios Within the Sandbox
Even with the sandbox intact, a malicious or compromised WebAssembly module can cause damage through the capabilities it has been granted:
Cryptomining. WebAssembly's near-native performance makes it effective for cryptocurrency mining. Several in-browser cryptojacking campaigns have used WebAssembly for their mining payloads. The sandbox does not prevent this -- it only requires CPU time, which the browser freely provides.
Data exfiltration. If the module has network access (through JavaScript in the browser or WASI in server environments), it can exfiltrate data. The sandbox prevents unauthorized memory access, but any data the module legitimately processes can be sent to an attacker-controlled endpoint.
Denial of service. Memory exhaustion, infinite loops, and CPU-intensive computation can all be performed within the sandbox. Browser mitigations (script timeout dialogs, process isolation) limit the impact, but server-side WebAssembly deployments may not have equivalent protections.
Side-channel information leakage. Timing variations in WebAssembly execution can leak information about data being processed. This is particularly relevant for WebAssembly modules that perform cryptographic operations.
Hardening Strategies
Verify module provenance. Build WebAssembly modules from source in your own build pipeline rather than using pre-compiled binaries. If you must use pre-compiled modules, verify them against published source code using reproducible builds.
Minimize granted capabilities. In WASI environments, grant only the capabilities the module needs. In browser environments, limit the JavaScript APIs that WebAssembly code can access through its imports.
Implement resource limits. Set memory limits, execution time limits, and stack depth limits. Most WebAssembly runtimes support these configurations.
Monitor execution patterns. Unexpected CPU usage, memory allocation patterns, or network activity from WebAssembly modules may indicate compromise.
How Safeguard.sh Helps
Safeguard.sh tracks WebAssembly dependencies that enter your project through npm packages or other package managers, providing visibility into the binary components in your supply chain. Its SBOM generation identifies WebAssembly modules within your dependency tree, and vulnerability monitoring flags known issues in the libraries those modules were compiled from. For organizations adopting WebAssembly in production, Safeguard.sh provides the supply chain oversight that the WebAssembly ecosystem's tooling does not yet offer natively.