WebAssembly
Segurança
Plugins
Sandbox
Multi-tenant

Wasm for plugins and sandbox: running third-party code safely

How WebAssembly's capabilities-based security model makes Wasm the best option for plugin systems and untrusted code execution across platforms.

Every successful platform reaches a point where it needs to let others write code that runs within it. User plugins, custom enterprise client functions, partner extensions, business rules sent via API. The problem is always the same: how do you run code you didn't write, on infrastructure you control, without turning that opening into a vulnerability? Traditional responses are expensive, slow or fragile. WebAssembly offers a different answer—and understanding why requires understanding what makes the problem difficult.

Why traditional solutions don’t scale

Many teams' first attempt is eval() or equivalent: executing the code string directly at runtime. It's quick to implement and catastrophic to maintain. The plugin code has access to everything the host process has — memory, network, file system. A malicious or simply faulty plugin can bring down the entire process or exfiltrate data from other tenants.

The second attempt is a plugin microservice: each extension runs in an isolated container. It works from a security point of view, but the operational cost grows linearly with the number of plugins. Maintaining one container per client is unfeasible on platforms with hundreds of extensions. The latency of each cross-container call also penalizes operations that should be sub-millisecond.

Child processes with Linux namespaces are another option — lighter than containers, but with the initialization overhead and complexity of seccomp and cgroups to ensure true isolation. It requires a team that deeply understands the kernel model. The common problem with all of these approaches is that they treat isolation as something external: you build a fence around untrusted code using operating system mechanisms. Wasm reverses this logic.

The capabilities model: zero by default

A WebAssembly module starts with zero capabilities. Literally none. He cannot open a file. Unable to make a network request. Cannot read environment variables. It cannot access any bytes outside of its own linear memory. If the module attempts any of these operations without the host having explicitly made the corresponding interface available, the operation fails — not at runtime with an exception, but structurally, because the function the module calls simply does not exist in the execution environment.

This is called capabilities-based security, and it is conceptually different from the ambient authority model that native code inherits. When you load a native library, it runs with full process privileges. When you load a Wasm module, it starts without any privileges and you, as the host, decide what to deliver.

The security interface is in the host integration code. You expose to the module exactly the functions that make sense — access to the Figma canvas API, but not the file system; access to Shopify order data, but not database credentials. The module does everything you allowed it to do, and nothing more. The attack surface is explicitly stated, not inferred.

How real platforms use it

Figma is the best-known example. The plugin system runs each plugin within a Wasm sandbox. The plugin receives access to the canvas API — it can read and modify elements, create layers, access text properties — but it does not have access to anything outside that contract. A plugin cannot read operating system files or make arbitrary network calls. This is not usage policy; It is a technical impossibility. That's why you can install a Figma plugin from an unknown developer with reasonable confidence that it won't exfiltrate your files.

Shopify made a similar decision to Shopify Functions: custom logic for discounts, cart validation and shipping rules is sent by merchants as Wasm modules. Each invocation receives the request data, executes within strict CPU and memory limits per call, and returns the result. A merchant with poorly written code does not crash the platform or access data from other merchants.

Envoy Proxy uses the same model for custom traffic filters. Companies that operate Envoy as a proxy — Istio and AWS App Mesh are examples — can write Wasm filters that process requests and responses in transit. The filter has access to the headers and body, but nothing to the internal state of the proxy. Extensibility without opening the system core. Game engines arrived at the same model through independent paths: modding systems that allow players to add content need to run strangers' code without compromising the host game, and Wasm solves this with the same capabilities mechanism.

The cost for those who write plugins

This security comes at a price. Writing a plugin for a Wasm-based platform is more difficult than writing JavaScript or Python.

The first friction is the toolchain: compiling for Wasm requires a compatible compiler — Rust and C/C++ have mature support, Go has experimental support, Python and Ruby arrive with limitations. The second is system access: within the sandbox, there is no direct access to anything other than what the host has exposed. Libraries that make direct HTTP calls do not work if the host has not made the corresponding interface available. This forces design discipline which can be frustrating at first.

On the platform side, the complexity lies in well defining the API exposed to the module. A poorly designed API is either too restrictive — plugins don't do what they need — or too permissive, compromising security. This contract is product and safety work as much as engineering.

When does it make sense to invest in this model

The decision has a clear profile. It makes sense when you are building a platform with external developers whose code quality you cannot guarantee. It makes sense when you need customization per tenant with individual resource limits — each client has its logic, but none monopolize CPU or memory. It makes sense when you distribute code that will run on infrastructure that you don't completely control.

It doesn't make sense when the plugins are in-house and you trust the team that writes them. Toolchain overhead and system constraints create real unmatched friction when the threat you want to mitigate doesn't exist in your model. The bottom line is this: extensibility outward, to an audience you don't control, is where Wasm delivers.

Also read