Course contentsShow
← Rust
Lesson 1848 of 1,91016. Specialized Runtime TargetsFree lesson

Security Boundaries for Wasm

Implement capability-based security patterns to restrict the host access of untrusted Wasm modules.

In this lesson, you will learn how to enforce fine-grained security boundaries by replacing ambient authority with capability-based access patterns within your Wasm runtime.

The Problem: Ambient Authority

By default, a Wasm module often relies on "ambient authority"—the assumption that if a module is allowed to talk to the host, it can talk to anything the host has access to (like the filesystem or network). In an untrusted environment, this is a security nightmare. If the module is compromised, the attacker inherits the full privileges of your host process.

Implementing Capability-Based Security

Instead of providing a global, unrestricted API, we implement Capabilities. A capability is an opaque, non-forgeable token (often a struct or a file descriptor index) that grants access to a specific, limited resource. If a module doesn't hold the token, it simply cannot interact with the corresponding host function.

Consider this pattern where we pass an explicit "resource handle" to our host exports:

// The host-defined capability structure
pub struct FileSystemCap {
    allowed_dir: String,
}

// We pass the capability explicitly via the Wasm-Bindgen boundary
#[wasm_bindgen]
pub fn write_to_file(cap: &FileSystemCap, path: &str, data: &[u8]) -> Result<(), String> {
    // We check the capability before acting
    if !path.starts_with(&cap.allowed_dir) {
        return Err("Access Denied: Path outside of scope".into());
    }
    
    // Perform the safe I/O here
    Ok(())
}

By requiring FileSystemCap as an argument, we move away from global state. In your host environment, you decide which modules receive which capabilities during initialization. If a module isn't passed the FileSystemCap during its instantiation phase, the Wasm code lacks the Import interface necessary to reach the filesystem, effectively sandboxing it into a "pure" execution environment.

This pattern treats authority as data. Because Wasm modules cannot synthesize these capabilities out of thin air (if we manage our imports strictly), we effectively shrink the attack surface to only what is explicitly shared.

Key Takeaway: Replace global API access with explicit capability objects passed into module imports to ensure that untrusted Wasm modules can only access the specific resources you have explicitly provisioned for them.