Stream: wasmtime

Topic: host-side middlewares for information flow control


view this post on Zulip Luiz Ribeiro (Sep 24 2026 at 19:23):

Hi all! I'm somewhat new to wasm and wasmtime. I'm currently exploring information flow control for wasm plugins. The idea is to label data when a plugin reads it (e.g. a file, an HTTP response) and block it from reaching sinks it shouldn't (the network, stdout, other files).

To see every source and sink, I've been building a middleware layer for wasmtime hosts. It's basically a chain of before/after hooks that run around every call crossing the host boundary (including the host's own imports, the component's exports and WASI p2/p3). Hooks can deny calls, and they also see the resource handles each call takes/returns, which lets a label follow data from, say, a file descriptor to the stream read from it.

Since wasmtime has no hook for intercepting calls AFAICT, and a Linker can't hand back a definition to wrap, I register my own implementation of each interface instead, which runs the chain and then forwards to the original. For p3 streams, whose data moves outside of calls, the host swaps in its own stream and runs the chain on each chunk.

Has anyone done something similar? Is this a terrible idea, or is there a better approach? I looked at composition (splicer, WASI-Virt), but if I understand correctly those can't reach host-provided imports, which is where most sources and sinks live.

view this post on Zulip fitzgen (he/him) (Sep 24 2026 at 19:26):

I'd recommend looking into using component composition for this kind of thing

view this post on Zulip Justin Fagnani (Sep 25 2026 at 02:13):

Hi Luiz!

I'm doing almost the exact same thing: Components are dynamically loaded into a host that uses Wasmtime. Every wasi: interface provided is a proxy to control and/or deny access, also for IFC (though my current system is very coarse-grained and probably not technically IFC yet). Users or workflow definitions (pre-configured graphs of components) can enable access to sensitive sinks with a permissions system.

I'm curious in both the interface proxy implementations, and what you're using components and IFC for (I have a guess). Maybe we could connect off-forum on the IFC bits.

view this post on Zulip Luiz Ribeiro (Sep 26 2026 at 02:47):

@Justin Fagnani exciting to hear of others working on similar things! :slight_smile:

At a high level I'm looking for ways to build applications that allow third-party plugins, where plugins need explicit user consent to access sensitive resources, and where data flows between the host and its plugins (and maybe between plugins) are tracked. Does that sound similar to your use case?

So far I've tried three approaches for the layer that intercepts calls between plugins and the host:

I also looked into splicer, but AFAICT it only inserts middleware on edges between components inside a composition, so it can't reach host imports.

I'm leaning towards composition now, but haven't committed yet. Are your proxies hand-written per interface? And yes, I'd love to connect off-forum!

view this post on Zulip Luiz Ribeiro (Sep 26 2026 at 03:01):

@fitzgen (he/him) thanks for the pointer! I prototyped the composition approach and it worked well on Wasmtime. Is there a reason beyond portability to prefer it over wrapping wasmtime-wasi's implementations on the host? E.g. are its generated traits not meant to be used this way?

view this post on Zulip Luiz Ribeiro (Sep 26 2026 at 03:05):

One component-model question I ran into, if anyone knows: to observe when a plugin closes a p3 stream (e.g. the one passed to write-via-stream), the wrapper has to relay its bytes after the sync call returns. I ended up with a second, long-running export that the host drives alongside the plugin's. Is there a more idiomatic way? (jco 1.35 doesn't seem to run two exports concurrently, so this part didn't work there)

Thanks again for all your responses and help here!

view this post on Zulip Victor Adossi (Sep 29 2026 at 13:49):

Hi @Luiz Ribeiro would you mind sharing a bit more about the failure you saw with Jco? A reproducer would be really helpful or even just a more in depth explanation for what wasn't working would be great!

view this post on Zulip fitzgen (he/him) (Sep 29 2026 at 14:54):

Luiz Ribeiro said:

fitzgen (he/him) thanks for the pointer! I prototyped the composition approach and it worked well on Wasmtime. Is there a reason beyond portability to prefer it over wrapping wasmtime-wasi's implementations on the host? E.g. are its generated traits not meant to be used this way?

With composition, you also put your code inside the sandbox, so it doesn't need to be part of the TCB, but if wrapping traits is working well for you then by all means

view this post on Zulip Luiz Ribeiro (Sep 30 2026 at 02:34):

Victor Adossi said:

Hi Luiz Ribeiro would you mind sharing a bit more about the failure you saw with Jco? A reproducer would be really helpful or even just a more in depth explanation for what wasn't working would be great!

@Victor Adossi thanks for following up! The concurrent exports thing turned out to be the wrong root cause. The actual problem was that a resource returned by an async host import ends up in the wrong handle table when the component is part of a composition. I've filed an issue with a repro here: https://github.com/bytecodealliance/jco/issues/2182, and opened a PR with a fix: https://github.com/bytecodealliance/jco/pull/2183

Fair warning that I leaned heavily on AI for the investigation and fix as I'm not familiar with jco's internals, so it could use a careful look.

view this post on Zulip Victor Adossi (Sep 30 2026 at 05:30):

Thanks @Luiz Ribeiro -- I'll take a look at the issue and the fix! Some of this might be fixed by a recently released version of componentize-js but I appreciate the contribution :)


Last updated: Oct 11 2026 at 02:20 UTC