Software Engineering

Customer Plugins Without Giving Away the Host: A Practical WebAssembly Boundary

TuniCyberLabs Team
Archive date:
Published
7 min read

WebAssembly can support product extensions with explicit interfaces. The engineering work is deciding what each plugin may access, consume and change.

A software product reaches an awkward stage when customers want their own rules inside a shared workflow. One needs a specialist pricing calculation; another needs a document transformation. Adding every variation to the core application makes releases harder to coordinate, while executing arbitrary customer code creates a different set of risks.

WebAssembly offers an option for a defined extension boundary. A host application loads a module or component and exposes a limited interface. The interesting product decision is not whether code can run in a sandbox. It is which capabilities, resources and business effects that code should receive.

Start with the extension you actually need

Imagine a fictional logistics SaaS product that lets each customer calculate a handling surcharge. The inputs are a small shipment description and a versioned rate configuration. The output is a proposed amount with an explanation. The customer does not need direct database access, the ability to read other tenants or a general network client.

This is a promising boundary because the calculation can be expressed as bounded input and output. The host can validate the result and decide whether to apply it. The plugin supplies a calculation; the application retains responsibility for authorisation, accounting and the final business transaction.

Contrast that with a plugin expected to run indefinitely, browse arbitrary websites and modify several external systems. Those requirements need a much wider operational model. WebAssembly does not remove the need to design that model or make every workload a good fit.

The interface is the product contract

Wasmtime's plugin application example uses WIT to describe functions exported by plugins and imports provided by the host. The example demonstrates a useful architectural idea: define the boundary before implementing the extension.

For the surcharge feature, specify field meanings, units, missing-value behaviour and output limits. Decide how the host reports invalid input, an unsupported interface version or a failed execution. A customer should not need to infer these rules from an internal implementation.

Keep the first interface narrow. Every additional host function becomes another permission and compatibility obligation. A generic database query function may seem flexible, but it transfers too much of the application's data boundary into plugin code. A specific operation with server-side tenant checks is easier to reason about.

Capabilities determine what the sandbox can reach

Wasmtime's security documentation describes capability-based filesystem access: applications can access files and directories they have been given. This is useful isolation, but the host still chooses what to expose. A broad host API can grant broad power regardless of the module's isolation from other memory.

Treat each import as an access decision. Does the plugin need a clock, randomness, temporary storage or an external lookup? Can the host perform that lookup itself and pass a bounded result instead? Use tenant context controlled by the host rather than trusting a tenant identifier supplied by the plugin.

Also review output. Plugin-generated text can appear in logs, reports or user interfaces. Apply the same validation and rendering rules you would apply to other untrusted input. Sandboxing computation does not make the resulting string safe for every destination.

Memory isolation does not allocate a fair share of compute

A plugin can be unable to read another tenant's memory while still consuming too much CPU or producing excessive output. Product owners therefore need an execution budget as well as an access boundary.

Wasmtime documents fuel and epoch-based interruption. Fuel offers deterministic interruption based on instrumented execution, while epochs provide a different, lower-overhead interruption approach. These mechanisms have different trade-offs; neither should be presented to customers as a universal wall-clock guarantee.

The engineering design must separately bound memory, output, concurrency and host calls. An imported operation that waits on an external service needs its own timeout and cancellation behaviour. Measure representative plugins and deliberate failure cases in the selected runtime configuration before setting customer-facing limits.

Decide what happens when a plugin fails

In the logistics example, a failed surcharge calculation might pause the quote for review rather than silently apply zero. The correct behaviour depends on the product's business rules. It should be visible to the customer and support team, with enough diagnostic information to identify the plugin version involved.

Avoid writing business state halfway through a calculation. Where possible, let the plugin propose a result and let the host validate and commit it. If an extension genuinely needs side effects, specify their retry and idempotency behaviour so a timeout cannot cause the same operation to happen twice.

Our tenant-isolation guide covers the surrounding SaaS access model. A plugin boundary belongs inside that model and must preserve it through errors, retries and administrative actions.

Version the ecosystem you are creating

Supporting customer code creates a compatibility commitment. Record the plugin artifact, interface version and approved capabilities. Decide whether customers can upload directly, whether review is required and how an older version can be restored after a bad release.

Runtime updates need regression testing against a representative plugin set. Portability still depends on supported interfaces, language tooling and host behaviour. A component running in one environment is evidence for that configuration, not proof that every runtime will behave identically.

A pilot should compare the plugin approach with a simpler configuration language or a separate service. If customers only need a small set of rules, ordinary configuration may be easier to maintain. WebAssembly becomes useful when the additional programmability justifies the interface and operations work.

For a product that needs controlled extensions, explore Custom Software Development, then describe one customer rule and the data it needs. TuniCyberLabs can help define a small extension boundary and evaluate whether WebAssembly is appropriate for it.

TAGS
WebAssemblyWasmtimeSaaS ArchitecturePlugin Security

Frequently Asked Questions

Does WebAssembly make a customer plugin automatically safe?

+

No. The runtime provides isolation mechanisms, but the host still controls capabilities, tenant authorisation, resource limits and output handling. Those boundaries require explicit design and testing.

Should a pricing plugin write directly to the database?

+

A narrower design lets it return a proposed calculation while the host validates and commits the result. Direct side effects require additional permissions, retry rules and transaction design.

When is a WebAssembly plugin unnecessary?

+

If customer variation fits a small configuration model, a rules form or configuration language may be simpler. Evaluate a plugin runtime when customers need meaningful programmability and the support commitment is justified.

Need help with
this topic
?

Our team specializes in the technologies and strategies discussed in this article. Let’s talk about how we can help your business.

Get in Touch