CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Dashboard
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-27204
6.9

Infinite Appetites: Breaking Wasmtime with CVE-2026-27204

Alon Barad
Alon Barad
Software Engineer

Feb 25, 2026·7 min read·5 visits

PoC Available

Executive Summary (TL;DR)

Wasmtime trusted guest modules too much. By asking for massive buffers or opening infinite resource handles, a guest could crash the host process (OOM) or stall it indefinitely. Fixed in version 42.0.0 by introducing 'fuel' for host calls and hard limits on resource tables.

A fundamental architectural oversight in Wasmtime's handling of the WebAssembly System Interface (WASI) and Component Model allowed malicious guests to exhaust host resources. By failing to budget or validate guest-provided parameters for resource allocation, Wasmtime enabled trivial Denial of Service attacks via memory exhaustion, handle saturation, and CPU loops during data transfer.

The Hook: The Sandbox That Wasn't

WebAssembly is sold on the premise of the perfect sandbox. It's the digital equivalent of a padded cell: the code inside can scream and thrash all it wants, but it can't hurt the facility. That's the theory, anyway. In practice, the sandbox is only as strong as the interface between the guest (the prisoner) and the host (the warden). In Wasmtime, this interface is defined by WASI (WebAssembly System Interface) and the Component Model.

Here is the problem: Wasmtime was a polite warden. If the prisoner asked for a glass of water, Wasmtime gave it to them. If the prisoner asked for a swimming pool, Wasmtime tried to build one inside the cell until the entire prison collapsed. CVE-2026-27204 isn't a buffer overflow in the traditional 1990s sense; it's a logic flaw where the host implementation implicitly trusted the guest's resource demands.

This vulnerability strikes at the heart of the serverless / edge computing model. If you are running multi-tenant Wasm workloads (Cloudflare Workers, Fastly Compute, or your own internal platform), you are relying on Wasmtime to keep Tenant A from nuking the server shared with Tenant B. With this bug, Tenant A simply had to ask nicely, and the host would commit suicide via Out-Of-Memory (OOM) panic.

The Flaw: Trusting the Untrustworthy

The root cause is a classic 'Unchecked Allocation' issue, specifically mapped to CWE-770 and CWE-400. In Rust, the language powering Wasmtime, memory safety is paramount, but resource safety is a logic problem, not a compiler problem. When a Wasm guest calls a host function (a 'hostcall'), it often passes parameters indicating how much data it wants to send or receive.

Prior to the fix, Wasmtime's implementation of WASIp1, WASIp2, and the Component Model treated these parameters as gospel. If a guest invoked wasi:random/get-random-bytes and requested 4GB of entropy, the host would obediently attempt to allocate a Vec<u8> of that size. In Rust, if a standard allocation fails, the program panics. A panic in the host library crashes the entire runtime process. Game over.

It wasn't just memory. The ResourceTable—the structure tracking open files, sockets, and futures—had no maximum capacity. A guest could enter a tight loop creating 'resources' (handles) without ever freeing them. Since the host tracks these in a HashMap or similar structure, the guest could linearly expand the host's memory footprint or exhaust system-wide file descriptors, affecting every other process on the machine.

The Code: Allocation Without Limits

Let's look at a simplified representation of the vulnerable logic versus the patched logic. The vulnerability existed in the 'lifting' and 'lowering' code—the glue that translates Wasm types into Rust types.

The Vulnerable Pattern (Conceptual):

// Guest calls get_random_bytes(len: u64)
fn get_random_bytes(&mut self, len: u64) -> Result<Vec<u8>> {
    // DANGER: No validation on 'len'. 
    // If guest sends u64::MAX, the host attempts a massive allocation.
    let mut buf = vec![0u8; len as usize]; 
    getrandom::fill(&mut buf)?;
    Ok(buf)
}

If len is huge, vec! triggers an allocation that the OS refuses, leading to an immediate abort of the Wasmtime process.

The Fix (Fuel and Caps):

The fix introduces the concept of HostcallFuel and explicit limits. It forces the host to check if it can afford the operation before attempting it.

fn get_random_bytes(&mut self, len: u64) -> Result<Vec<u8>> {
    // 1. Check against specific API limit
    if len > self.limits.max_random_bytes {
        bail!("requested too many bytes");
    }
 
    // 2. Charge 'fuel' for the allocation cost
    self.fuel.charge_allocation(len)?;
 
    // Safe to allocate now (mostly)
    let mut buf = vec![0u8; len as usize];
    getrandom::fill(&mut buf)?;
    Ok(buf)
}

The patch actually goes deeper, implementing Store::set_hostcall_fuel to meter data movement across the boundary. It prevents the 'Quadratic Blowup' where nested data structures (like a list of lists) could cause the host to do exponentially more work than the guest paid for.

The Exploit: The OOM Cannon

Exploiting this is trivially easy and requires zero knowledge of memory layout or ROP chains. You don't need to bypass ASLR; you just need to be annoying. Here is how an attacker would weaponize this in a multi-tenant environment.

Attack Vector 1: The Allocation Bomb

The attacker compiles a WASM module that imports wasi:random/random (or any API returning a list/string). The WAT (WebAssembly Text) would look something like this:

(module
  (import "wasi:random/random" "get-random-bytes" (func $get_random (param i64) (result i32)))
  (func (export "_start")
    ;; Ask for 4GB of data. 
    ;; The host tries to allocate this in RAM immediately.
    (call $get_random (i64.const 4294967295))
    drop
  )
)

When Wasmtime executes this, the allocator returns null (or panics), and the OS kills the process. If this Wasmtime instance is hosting 50 other customers, they all go offline instantly.

Attack Vector 2: The Handle Leak

If the host has lots of RAM but strict file limits, the attacker targets the ResourceTable. By repeatedly creating dummy resources (like TCP sockets or files) and never closing them, the attacker fills the ResourceTable. Since there was no max_capacity check, the table grows until the host runs out of file descriptors (EMFILE) or hits the memory limit. This is a slower, creeping death compared to the instant kill of the Allocation Bomb.

The Impact: Asymmetric Warfare

The severity of this vulnerability is defined by its asymmetry. A WASM module might weigh only 10KB. The request to trigger the bug is a handful of bytes. Yet, the impact is the total cessation of the host service.

In a cloud context, this is a catastrophic 'Neighbor Noise' issue. Imagine a Function-as-a-Service (FaaS) provider running Wasmtime. One malicious user creates a free account, deploys the 'OOM Cannon', and repeatedly hits the endpoint. Every time a worker node picks up the job, it dies. The attacker can effectively sweep through the provider's fleet, knocking over nodes like dominoes.

Furthermore, because the crash often manifests as a process abort (SIGABRT/SIGKILL), it leaves very little trace in application logs. The metrics just stop. Ops teams see nodes vanishing without stack traces, making debugging a nightmare unless you are monitoring memory pressure in real-time.

The Fix: Metering the Metropolis

The Bytecode Alliance patched this by introducing bureaucracy—the good kind. They added 'knobs' that embedders can (and must) turn.

1. Hostcall Fuel: This is distinct from standard Wasm execution fuel. It specifically budgets the bytes copied in and out of the guest. If a guest tries to copy 1GB of data but only has 1MB of fuel, the trap triggers before the allocation happens.

2. Resource Limits: The ResourceTable now supports a max_capacity. If a guest tries to open the 1,000,001st file handle, the host returns an error instead of crashing.

3. API-Specific Limits: Hard caps on things like wasi:http header sizes and wasi:random return buffers.

> [!WARNING] > The Trap for the Unwary: If you are using the backported fixes (versions 41.0.4, 40.0.4, etc.), the defaults are still unbounded to preserve backward compatibility. You are NOT safe just by updating. You must explicitly configure the limits in your Config code.

Only version 42.0.0 and later enables safe defaults (e.g., 1000 handles max) out of the box. If you are running older versions, you are driving a car with no brakes unless you manually install them.

Official Patches

Bytecode AllianceWasmtime v42.0.0 Release Notes

Fix Analysis (1)

Technical Appendix

CVSS Score
6.9/ 10
CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:P/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H

Affected Systems

Wasmtime Runtime (Rust)Cloudflare Workers (Historical/Potential)Fastly Compute (Historical/Potential)Fermyon SpinAny Rust application embedding `wasmtime` crate

Affected Versions Detail

Product
Affected Versions
Fixed Version
Wasmtime
Bytecode Alliance
< 24.0.624.0.6
Wasmtime
Bytecode Alliance
>= 25.0.0, < 36.0.636.0.6
Wasmtime
Bytecode Alliance
>= 37.0.0, < 40.0.440.0.4
Wasmtime
Bytecode Alliance
>= 41.0.0, < 41.0.441.0.4
AttributeDetail
CWE IDCWE-770 (Allocation without Limits)
CVSS 4.06.9 (Medium)
Attack VectorNetwork (Guest-to-Host)
ImpactDenial of Service (DoS)
Exploit StatusTrivial (PoC Available)
KEV StatusNot Listed

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
T1499.004Application Exhaustion
Impact
CWE-770
Allocation of Resources Without Limits or Throttling

Allocation of Resources Without Limits or Throttling

Known Exploits & Detection

N/AExploitation involves calling WASI APIs with MAX_INT lengths.

Vulnerability Timeline

Vulnerability Disclosed
2026-02-24
Patches Released (v42.0.0)
2026-02-24

References & Sources

  • [1]GHSA Advisory
  • [2]Wasmtime Documentation

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.