Apr 10, 2026·5 min read·4 visits
Wasmtime's Winch compiler fails to properly translate global table indices to defined table indices during `table.fill` operations, allowing a guest module to crash the host runtime (DoS) by triggering a bounds check panic.
A moderate-severity vulnerability in the Wasmtime Winch compiler backend allows a malicious WebAssembly guest module to trigger a host panic via an out-of-bounds array access. The flaw stems from a regression during table index refactoring where Winch was not updated to distinguish between global and defined table indices.
Wasmtime is an open-source runtime for WebAssembly, featuring multiple compiler backends. The Winch compiler backend is designed as a baseline compiler optimizing for compilation speed over execution performance. It operates alongside the primary Cranelift optimizing compiler.
The vulnerability, identified as CVE-2026-34946, resides within the Winch compiler's handling of the table.fill WebAssembly instruction. When a compiled guest module executes this specific instruction, the host runtime may encounter an unhandled Rust panic. This defect is classified under CWE-670 (Always-Incorrect Control Flow Implementation).
The primary consequence is a reliable Denial of Service (DoS) against the host application embedding Wasmtime. An alternative consequence involves spec-incorrect execution where the guest modifies an unintended table memory region. Memory safety is not compromised due to Rust's bounds checking guarantees.
The defect originates from a desynchronization between Wasmtime's core runtime data structures and the code emitted by the Winch compiler. A prior structural refactoring in Wasmtime (PR #11254) altered the internal representation of WebAssembly tables. This update introduced a strict distinction between global module table indices (TableIndex) and instance-specific defined table indices (DefinedTableIndex).
When executing table operations, host-side library calls expect the caller to provide a DefinedTableIndex. This index is used to look up metadata within a defined tables array specific to the executing instance. The Winch compiler was omitted from the updates associated with this refactoring.
Consequently, Winch's code generation logic continued to emit instructions that pass the global TableIndex to the host libcalls. If a guest module imports tables, the global indices for locally defined tables are shifted upward. This shifting causes the global TableIndex to numerically exceed the corresponding DefinedTableIndex.
To understand the failure state, we examine the expected behavior of table interactions in WebAssembly. When a module imports tables, the global table index space reserves the lowest indices for the imports. Locally defined tables occupy the subsequent indices. When Winch passes a local table's global index to a host function expecting an array offset starting from zero, the index is artificially inflated.
The host runtime performs a strict bounds check on the defined tables metadata array using this supplied index. Because the index incorporates the offset of the imported tables, it routinely points beyond the end of the array. This out-of-bounds access immediately triggers a standard Rust bounds check failure (panic!).
The fix implementation addresses the semantic gap between logical module indices and runtime implementation offsets. The patch modifies the Winch compiler to correctly translate the logical index before invoking host functions.
Commit 96dde3aa67a5c456e4091ed60a9e3e774f0efd85 introduces internal helper functions to handle table resolution correctly. These helpers determine whether a table is imported or defined, and translate the logical TableIndex into the correct DefinedTableIndex runtime offset before the value is utilized by the host logic.
Exploitation requires the attacker to supply a crafted WebAssembly module to a host environment using the Winch compiler backend. The environment must accept and execute untrusted WebAssembly binaries. No authentication is inherently required unless enforced by the specific host application.
The attack vector relies on the inclusion of specific WebAssembly instructions and a targeted module structure. The attacker constructs a module that imports at least one table, effectively shifting the global index of subsequent locally defined tables. The module then invokes the table.fill instruction targeting a locally defined table.
The regression test provided by the maintainers serves as a clear proof-of-concept. The module imports a table $t1 and defines a second table $t2. When table.fill is executed against $t2, the unpatched Winch compiler passes the global index (1) instead of the defined index (0) to the host.
(module
(import "t" "t" (table $t1 1 funcref))
(table $t2 2 funcref)
(func (export "fill2") (param i32 funcref i32)
local.get 0
local.get 1
local.get 2
table.fill $t2)
)The primary impact of CVE-2026-34946 is a Denial of Service condition affecting the Wasmtime host application. Because the out-of-bounds read triggers an unhandled Rust panic, the entire host process terminates abruptly. This abrupt termination provides a reliable mechanism for an attacker to disrupt services relying on the Wasmtime engine.
This vulnerability achieves a CVSS v4.0 score of 5.9. The vector string CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:P/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N reflects high availability impact against the vulnerable system, with no confidentiality or integrity consequences. The attack complexity is low, but relies on the host exposing module compilation capabilities.
In specific edge cases where the index bounds check does not fail (e.g., the module defines a sufficiently large number of tables), the mismatch results in the host modifying the incorrect table. This creates spec-incorrect behavior within the WebAssembly guest environment but does not compromise host memory or execution context.
The maintainers of the Bytecode Alliance have released official patches addressing this vulnerability in Wasmtime versions 36.0.7, 42.0.2, and 43.0.1. Administrators must update the host application's Wasmtime dependency to a secure version to prevent the host panic condition.
If immediate patching is not feasible, mitigation can be achieved by disabling the Winch compiler backend entirely. Reverting to Wasmtime's default Cranelift compiler removes the vulnerable code path, as Cranelift correctly implements the table index translation logic required by the host runtime.
Additionally, host applications can implement pre-compilation validation modules. Security engineers can configure static analysis checks to reject incoming WebAssembly modules containing both imported tables and the table.fill instruction, effectively neutralizing the required exploitation preconditions.
CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:P/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Wasmtime Bytecode Alliance | >= 25.0.0, < 36.0.7 | 36.0.7 |
Wasmtime Bytecode Alliance | >= 37.0.0, < 42.0.2 | 42.0.2 |
Wasmtime Bytecode Alliance | >= 43.0.0, < 43.0.1 | 43.0.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-670 |
| Attack Vector | Network / Local Module Execution |
| CVSS v4.0 Score | 5.9 (Moderate) |
| Impact | Denial of Service (Host Panic) |
| Exploit Status | Proof of Concept Available |
| Remediation | Patch Available |
Always-Incorrect Control Flow Implementation