Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions crates/wasmtime/RUSTSEC-0000-0000.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
```toml
[advisory]
id = "RUSTSEC-0000-0000"
package = "wasmtime"
date = "2026-10-27"
url = "https://github.com/bytecodealliance/wasmtime/issues/15024"
categories = ["code-execution", "denial-of-service", "format-injection", "memory-corruption", "memory-exposure", "privilege-escalation"]
cvss = "CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H"

[affected.functions]
"wasmtime::CodeBuilder::expose_unsafe_intrinsics" = [">= 39.0.0"]

[versions]
patched = []
unaffected = ["< 39.9.0"]
```
# Compile-time builtin composition resolves guest imports from host working directory

## Summary

Wasmtime composes builtins through `wasm-compose`'s `ComponentComposer`, which
falls back to searching on disk in the current working directory to satisfy
guest-chosen imports by name for CLI purposes, treating any file found at the
imported name’s path as trusted (in the same privilege as embedder builtins). A
component found on disk by a guest-chosen import name, as a result, can import
Wasmtime's unsafe intrinsics, which are native unchecked memory accesses to host
addresses meant to be exposed to legitimate, trusted builtins. This results in
arbitrary R/W by untrusted code and potential code execution. This violates the
[documented principle](https://docs.rs/wasmtime/latest/wasmtime/struct.CodeBuilder.html#method.expose_unsafe_intrinsics)
of the guest not being part of the trusted compute base.

## Details

Code is referenced against
[ec63b69](https://github.com/bytecodealliance/wasmtime/commit/ec63b69f3da9783db784eef6ba67635385926a2a).

The write process of Wasmtime's composition uses the filesystem as scratch
space, where
[`compile_time_builtins.rs` lines 23-43](https://github.com/bytecodealliance/wasmtime/blob/ec63b69f3da9783db784eef6ba67635385926a2a/crates/wasmtime/src/compile/code_builder/compile_time_builtins.rs#L39-43)
makes an import name into a path name verbatim and writes the builtin's bytes
to that path within a temporary directory with the shape
`<tempdir>/_deps/<import name>.wasm`. In the Wasm component model ecosystem,
interface names are conventionally shaped `ns:pkg/if@ver`, and by putting this
verbatim into the filesystem, the slash in the path allows for traversal, and
single letter namespaces resolve as drive letters on Windows. Versions with
dot-separated segments get their last segment chopped off on
[line 40](https://github.com/bytecodealliance/wasmtime/blob/ec63b69f3da9783db784eef6ba67635385926a2a/crates/wasmtime/src/compile/code_builder/compile_time_builtins.rs#L40)
by setting the extension to "wasm", making `ns:pkg/if@1.0.0` and
`ns:pkg/if@1.0.1` both become the filesystem path `<deps>/ns:pkg/if@1.0.wasm`,
potentially reverting a patch or obscuring its presence from other logic. The
colon in the path can also make it malformed on Windows, causing OS errors.

The composition read process begins in
[`code_builder.rs` lines 203-216](https://github.com/bytecodealliance/wasmtime/blob/ec63b69f3da9783db784eef6ba67635385926a2a/crates/wasmtime/src/compile/code_builder.rs#L203-L216),
calling `compose_compile_time_builtins`. `compile_time_builtins.rs` then creates
a default `Config` with an empty `dir` at
[line 32](https://github.com/bytecodealliance/wasmtime/blob/ec63b69f3da9783db784eef6ba67635385926a2a/crates/wasmtime/src/compile/code_builder/compile_time_builtins.rs#L32),
then,
[lines 50-51](https://github.com/bytecodealliance/wasmtime/blob/ec63b69f3da9783db784eef6ba67635385926a2a/crates/wasmtime/src/compile/code_builder/compile_time_builtins.rs#L50-L51)
compose with `ComponentComposer`, triggering the search on disk at `composer.rs`
[lines 128-166](https://github.com/bytecodealliance/wasm-tools/blob/cc0d3b77653571c75791291df7fa0c32bbb9405a/crates/wasm-compose/src/composer.rs#L128-L166)
via `find_component` and `parse_component` that try `dir.join(name)` with
".wasm" and ".wat", searching the host's working directory.

After composition, `translate.rs` lines
[934](https://github.com/bytecodealliance/wasmtime/blob/ec63b69f3da9783db784eef6ba67635385926a2a/crates/environ/src/component/translate.rs#L934)
and
[1810](https://github.com/bytecodealliance/wasmtime/blob/ec63b69f3da9783db784eef6ba67635385926a2a/crates/environ/src/component/translate.rs#L1810)
resolve the intrinsic import regardless of its provenance, and consequently, a
component found on disk this way is composed in alongside the embedder’s
builtins with the same standing, i.e. if it imports the Wasmtime intrinsics now
it receives the real ones.

The Wasmtime unsafe intrinsics allow callers to arbitrarily read and write host
process memory and are meant to be used only by legitimate builtins explicitly
trusted by the embedder. By the mechanisms previously mentioned, an untrusted
guest can traverse paths, cause errors with them, or name any modules to import
with the same standing as compile-time builtins, giving them access to the
unsafe intrinsics and compromising the trusted compute base.

PR [#15025](https://github.com/bytecodealliance/wasmtime/pull/15025) resolves
this by composing in-memory without using CLI machinery.
Loading