CVE
CVE-2026-115893, CVE-2026-115889, CVE-2026-115892
CWE
CWE-190, CWE-682, CWE-843, CWE-444
Affected Surface
- Rust crates `wasmtime` and `cranelift-codegen` prior to `36.0.19` (`cranelift-codegen 0.123.19`), `48.0.7` (`0.135.7`), `49.0.4` (`0.136.4`), and `50.0.0` (`0.137.0`) on `aarch64` targets (`CVE-2026-115893` / `GHSA-mghf-wjfp-p5xm`)
- Rust crates `wasmtime` and `cranelift-codegen` prior to `36.0.19` and `>= 37.0.0, < 43.0.0` on all architectures (`CVE-2026-115889` / `GHSA-897f-g5gm-fmxm`)
- Rust crate `wasmtime` versions `>= 46.0.0, < 48.0.7` and `>= 49.0.0, < 49.0.4` using Component Model `StreamAny` / `FutureAny` (`CVE-2026-115892` / `GHSA-9pvw-hwfg-92h5`)
- Rust crate `wasmtime-wasi-http` prior to `36.0.19`, `48.0.7`, `49.0.4`, and `50.0.0` (`GHSA-r8xh-cgf7-392j`, `GHSA-9prg-84vf-g5fc`, and `GHSA-jxcf-8qw5-5c33`)
TL;DR
On 23 and 24 October 2026, NVD, the GitHub Advisory Database, and RustSec published six advisories for Wasmtime (wasmtime, cranelift-codegen, and wasmtime-wasi-http), Bytecode Alliance’s WebAssembly runtime and compiler stack.
Two of the vulnerabilities are CVSS v3.1 9.9 Critical compiler miscompilations in Cranelift that allow an untrusted WebAssembly guest module to escape the Wasmtime sandbox under default engine settings:
CVE-2026-115893(GHSA-mghf-wjfp-p5xm,RUSTSEC-2026-0379, CVSS 9.9 Critical): Onaarch64hosts, Cranelift compiled each WebAssemblybr_tableinstruction into a single monolithic machine-instruction sequence (MInst.JTSequence) that began with a conditional branch (b.hs default) jumping over the inline 32-bit jump-table entries to the default block. BecauseJTSequenceforbids register-allocator spills and constant/branch veneers inside its body, and ARM64’s conditional branch (B.cond/LabelUse::Branch19) encodes a signed 19-bit word offset (+/- 1 MiB), abr_tablewith more than roughly 256,000 targets placed the default block beyond the 19-bit branch range, corrupting the conditional branch target so out-of-bounds indices jumped to an attacker-controlled offset in compiled code.CVE-2026-115889(GHSA-897f-g5gm-fmxm,RUSTSEC-2026-0380, CVSS 9.9 Critical): On all CPU architectures in Wasmtime< 36.0.19and37.0.0through42.x, Cranelift’s data-flow graph packed SSA value definitions (ValueDataPacked(u64)) into two 24-bit fields (x:24andy:24) and checked the 24-bit bound (16,777,215) usingdebug_assert!(). In release builds,encode_narrow_field()did not panic when an instruction, block, or SSA value index reached2^24 - 1; instead,decode_narrow_field()translated0xff_ffffinto the sentinel0xffff_ffff(u32::MAX) and higher indices truncated into adjacent bitfields, causing silent SSA value aliasing, type confusion, and sandbox escape.
The same patch train (36.0.19, 48.0.7, 49.0.4, and 50.0.0) also fixes a Component Model host panic when lowering type-erased StreamAny / FutureAny handles (CVE-2026-115892, GHSA-9pvw-hwfg-92h5) and three wasmtime-wasi-http flaws where a guest could emit duplicate Content-Length headers (GHSA-r8xh-cgf7-392j), mismatched spliced Content-Length values (GHSA-9prg-84vf-g5fc), or unfiltered HTTP trailers (GHSA-jxcf-8qw5-5c33).
Affected packages and projects
| Ecosystem | Crate | CVE / GHSA / RustSec | Severity | Affected versions | Fixed versions | Component |
|---|---|---|---|---|---|---|
| crates.io | wasmtime, cranelift-codegen | CVE-2026-115893 (GHSA-mghf-wjfp-p5xm, RUSTSEC-2026-0379) | CVSS 9.9 Critical | wasmtime < 36.0.19, >= 37.0.0, < 48.0.7, >= 49.0.0, < 49.0.4; cranelift-codegen < 0.123.19, 0.124.0..0.135.7, 0.136.0..0.136.4 | wasmtime 36.0.19, 48.0.7, 49.0.4, 50.0.0; cranelift-codegen 0.123.19, 0.135.7, 0.136.4, 0.137.0 | cranelift/codegen/src/isa/aarch64/inst/emit.rs and crates/cranelift/src/translate/code_translator.rs |
| crates.io | wasmtime, cranelift-codegen | CVE-2026-115889 (GHSA-897f-g5gm-fmxm, RUSTSEC-2026-0380) | CVSS 9.9 Critical | wasmtime < 36.0.19, >= 37.0.0, < 43.0.0; cranelift-codegen < 0.123.19, 0.124.0..0.130.0 | wasmtime 36.0.19, >= 43.0.0; cranelift-codegen 0.123.19, >= 0.130.0 | cranelift/codegen/src/ir/dfg.rs (ValueDataPacked / encode_narrow_field) |
| crates.io | wasmtime | CVE-2026-115892 (GHSA-9pvw-hwfg-92h5, RUSTSEC-2026-0378) | CVSS 5.7 Medium | >= 46.0.0, < 48.0.7, >= 49.0.0, < 49.0.4 | 48.0.7, 49.0.4, 50.0.0 | crates/wasmtime/src/runtime/component/concurrent/futures_and_streams.rs |
| crates.io | wasmtime-wasi-http | GHSA-r8xh-cgf7-392j, GHSA-9prg-84vf-g5fc, GHSA-jxcf-8qw5-5c33 | Medium / Low | < 36.0.19, >= 37.0.0, < 48.0.7, >= 49.0.0, < 49.0.4 (9prg and jxcf affect wasip3 in 48.x/49.x) | 36.0.19, 48.0.7, 49.0.4, 50.0.0 | crates/wasi-http/src/field_map.rs, src/lib.rs, src/p3/body.rs |
Technical analysis
1. CVE-2026-115893: aarch64 br_table 19-bit b.hs branch displacement overflow
On 64-bit ARM (aarch64), Cranelift lowered a WebAssembly br_table instruction into a single compound pseudo-instruction (Inst::JTSequence) in cranelift/codegen/src/isa/aarch64/inst/emit.rs. Keeping the sequence as one VCode instruction prevented the register allocator from inserting spills or reloads between the adr instruction and the inline jump table.
Before commit 222ff3a65d, JTSequence emitted a b.hs default conditional branch at the very top of the sequence, followed immediately by N 4-byte jump-table offsets (jt_entries) and then the target basic blocks:
// cranelift/codegen/src/isa/aarch64/inst/emit.rs (vulnerable)
// Branch to default when condition code from prior comparison indicates.
let br =
enc_conditional_br(BranchTarget::Label(default), CondBrKind::Cond(Cond::Hs));
let default_br_offset = sink.cur_offset();
sink.use_label_at_offset(default_br_offset, default, LabelUse::Branch19);
sink.put4(br);
// Overwrite the index with a zero when the above branch misspeculates (Spectre mitigation).
That generated the following machine-code layout:
cmp w0, #N ; compare table index against N
b.hs default ; 19-bit signed PC-relative branch (LabelUse::Branch19)
csel x11, xzr, x0, hs
csdb
adr x10, jt
ldrsw x11, [x10, x11, uxtw #2]
add x10, x10, x11
br x10
jt:
.word target_0 - jt ; 4 bytes per br_table target
.word target_1 - jt
...
In the A64 instruction set, B.cond (LabelUse::Branch19) has a 19-bit signed immediate field counting 4-byte instructions, giving a maximum forward reach of 2^18 - 1 = 262,143 instructions (1,048,572 bytes). Because the inline jump table jt sits directly between b.hs default and the default block label, a single br_table with more than ~256,000 targets pushes default past +1 MiB. Moreover, because JTSequence is emitted as an indivisible block, Cranelift’s MachBuffer island emitter cannot insert a branch veneer inside the table. When the label offset wraps the 19-bit field during relocation patching, b.hs jumps into the middle of the jump table or compiled guest code at an attacker-chosen offset.
The fix in 222ff3a65d removes the conditional branch from JTSequence altogether and enforces an explicit compiler limit of MAX_BR_TABLE_TARGETS = 65520 (matching V8 and SpiderMonkey):
--- a/cranelift/codegen/src/isa/aarch64/inst.isle
+++ b/cranelift/codegen/src/isa/aarch64/inst.isle
@@ -5194,14 +5194,18 @@
;; Helper for emitting `MInst.JTSequence` instructions.
;; Emit the compound instruction that does:
;;
-;; b.hs default
-;; csel rB, xzr, rIndex, hs
+;; mov rB, #N ; N = number of non-default targets
+;; csel rB, rIndex, rB, lo ; clamp out-of-bounds indices to N
;; csdb
;; adr rA, jt
;; ldrsw rB, [rA, rB, uxtw #2]
;; add rA, rA, rB
;; br rA
-;; [jt entries]
+;; jt: [N target entries] [default entry]
+;;
+;; The flags must be set by a comparison of `rIndex` against `N`.
+;; There is deliberately no conditional branch to the default target:
+;; its range would be limited, and the inline jump table may be large.
Instead of branching around the table on an out-of-bounds index, Cranelift now appends the default target as the final entry in jt (at index N) and uses csel rB, rIndex, rB, lo to clamp any index >= N to N. Both wasmtime-cranelift and winch-codegen also reject any Operator::BrTable with targets.len() > 65520 before reachability analysis.
2. CVE-2026-115889: silent 24-bit overflow in ValueDataPacked SSA value packing
To keep Cranelift’s IR compact, cranelift/codegen/src/ir/dfg.rs packed each SSA ValueData entry (Inst, Param, Alias, Union) into a single 64-bit integer (struct ValueDataPacked(u64)) with a 2-bit tag, a 14-bit Type, and two 24-bit operands x and y:
// cranelift/codegen/src/ir/dfg.rs in Wasmtime < 36.0.19 and 37.0.0..42.x
/// | tag:2 | type:14 | x:24 | y:24 |
struct ValueDataPacked(u64);
fn encode_narrow_field(x: u32, bits: u8) -> u32 {
let max = (1 << bits) - 1;
if x == 0xffff_ffff {
max
} else {
debug_assert!(
x < max,
"{x} does not fit into {bits} bits (must be less than {max} to \
allow for a 0xffffffff sentinel)"
);
x
}
}
fn decode_narrow_field(x: u32, bits: u8) -> u32 {
if x == (1 << bits) - 1 { 0xffff_ffff } else { x }
}
Look at what happens in a release build (cfg(not(debug_assertions))) when a large or crafted WebAssembly function allocates 2^24 - 1 = 16,777,215 (0x00ff_ffff) or more instructions, blocks, or SSA values:
debug_assert!(x < max)is compiled out completely.- When
x == 0x00ff_ffff(2^24 - 1),encode_narrow_field(x, 24)returns0x00ff_ffff, whichdecode_narrow_field()unpacks as0xffff_ffff(thereserved_valuesentinel). - When
x >= 0x0100_0000(2^24),encode_narrow_field()returnsxunchanged without masking it to 24 bits. InsideValueDataPacked::make(),(x as u64) << 24shifts bit 24 and higher directly into thetype:14field (or fromyintox), corrupting both the SSA value’s IRTypeand its referenced instruction or alias index.
Because optimization passes (such as e-graph / GVN alias resolution and bounds-check elimination) trust the Type and SSA value indices stored in ValueDataPacked, corrupting those fields lets a crafted Wasm function induce type confusion in Cranelift IR and escape the sandbox.
Commit ba8f7d70ca (landed in Wasmtime 43.0.0 via PR #12613 and backported to 36.0.19 in PR #14818) deletes encode_narrow_field() and decode_narrow_field() and replaces the 64-bit bitfield with a 10-byte packed struct that stores full 32-bit x and y indices:
#[repr(Rust, packed)]
struct ValueDataPacked {
x: u32,
y: u32,
flags_and_type: u16,
}
3. CVE-2026-115892 and wasmtime-wasi-http header framing fixes
CVE-2026-115892(GHSA-9pvw-hwfg-92h5): When a host embedder created a Component ModelStreamReader<T>orFutureReader<T>, passed it into a guest, received it back as a type-erasedStreamAnyorFutureAny(orVal::Stream/Val::Future), and then lowered it into another guest function expecting a different payload type,FutureAny::lower_to_indexandStreamAny::lower_to_indexmissed the payload-equivalence check for host-originated handles (TransmitOrigin::Host) and triggered a hostpanic!. Commit48dacc7624centralizes the check insidetypecheck_lowered_transmit()infutures_and_streams.rsso lowering returns a cleanErr("future or stream payload types differ").GHSA-r8xh-cgf7-392jandGHSA-9prg-84vf-g5fc(wasmtime-wasi-http):FieldMap::append()andset()previously allowed a WASI guest to attach multiple conflictingContent-Lengthheaders (Content-Length: 5andContent-Length: 6) whileget_content_length()only inspected the first one (headers.get(CONTENT_LENGTH)), enabling HTTP request smuggling through downstream proxies. In addition, onwasip3, splicing a body into a new response did not enforceself.sent == self.limitbefore reportingis_end_stream().FieldMapandget_content_length()now reject any message with more than oneContent-Lengthheader value.
Detection and remediation
1. Audit Cargo.lock for vulnerable wasmtime and cranelift-codegen versions
Run the following commands across your Rust workspaces:
# Check resolved versions of wasmtime, cranelift-codegen, and wasmtime-wasi-http
cargo tree -i wasmtime -i cranelift-codegen -i wasmtime-wasi-http 2>/dev/null || true
rg -n -A 3 '^name = "(wasmtime|cranelift-codegen|wasmtime-wasi-http)"' Cargo.lock 2>/dev/null
# If cargo-audit is installed, scan against the updated RustSec database (RUSTSEC-2026-0378..0380)
cargo audit 2>/dev/null || true
2. Upgrade to patched releases and clear precompiled .cwasm caches
- Upgrade to a patched release line:
- On the
49.xline: upgrade towasmtime >= 49.0.4(cranelift-codegen >= 0.136.4). - On the
48.xline: upgrade towasmtime >= 48.0.7(cranelift-codegen >= 0.135.7). - On the
36.xLTS line: upgrade towasmtime >= 36.0.19(cranelift-codegen >= 0.123.19). - If you are on an unmaintained intermediate release (
37.xthrough47.x), upgrade to48.0.7,49.0.4, or50.0.0.
- On the
- Invalidate serialized / AOT-compiled
.cwasmartifacts compiled from untrusted modules: BecauseCVE-2026-115893andCVE-2026-115889are code-generation bugs in Cranelift, any precompiled module (Engine::precompile_module/Module::serialize) produced by an unpatched compiler from an untrusted.wasminput already contains the miscompiled machine code. Recompile all cached artifacts after upgrading Wasmtime. - If you implement a custom
WasiHttpHooks::is_forbidden_headeronwasip3(GHSA-jxcf-8qw5-5c33): Also implementWasiHttpHooks::forbidden_header_filteron48.0.7/49.0.4(or migrate to50.0.0, whereforbidden_header_filterreplacesis_forbidden_header) so custom forbidden headers are stripped from forwarded HTTP body trailers.
Timeline
- 2026-02-23: Cranelift merges PR
#12613(ba8f7d70ca), replacing 24-bitValueDataPacked(u64)bit-packing with full 32-bitxandyfields for Wasmtime43.0.0. - 2026-10-19: Bytecode Alliance publishes
wasmtime36.0.19,48.0.7, and49.0.4(followed by50.0.0on 20 October) with commitsf517bd6e89,222ff3a65d, and994549891c. - 2026-10-23 (22:02 to 22:16 UTC): GitHub and NVD publish
CVE-2026-115889(GHSA-897f-g5gm-fmxm, CVSS 9.9 Critical),CVE-2026-115892(GHSA-9pvw-hwfg-92h5), andCVE-2026-115893(GHSA-mghf-wjfp-p5xm, CVSS 9.9 Critical). - 2026-10-24 (12:00 UTC): RustSec publishes
RUSTSEC-2026-0378,RUSTSEC-2026-0379, andRUSTSEC-2026-0380.
From research to remediation
Check whether this pattern exists in your codebase
Turn this research into a remediation workflow. Scan dependencies and package manifests for similar supply-chain risk, then prioritize fixes with reachability context.
References
- Wasmtime advisory GHSA-mghf-wjfp-p5xm (CVE-2026-115893: Cranelift aarch64 br_table sandbox escape)
- Wasmtime advisory GHSA-897f-g5gm-fmxm (CVE-2026-115889: Cranelift SSA ValueDataPacked overflow)
- Wasmtime advisory GHSA-9pvw-hwfg-92h5 (CVE-2026-115892: Component Model stream/future lowering panic)
- Wasmtime advisory GHSA-r8xh-cgf7-392j (wasi-http conflicting Content-Length headers)
- bytecodealliance/wasmtime commit 222ff3a65d (48.0.7 security fixes)
- bytecodealliance/wasmtime commit ba8f7d70ca (update ValueDataPacked to support full Value range)
- RustSec advisories RUSTSEC-2026-0378, RUSTSEC-2026-0379, and RUSTSEC-2026-0380
- NVD: CVE-2026-115893 and CVE-2026-115889