CVEReports
CVEReports

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

Product

  • Home
  • 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-27572
6.9

CVE-2026-27572: When 32,769 Headers Kill the Sandbox

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 24, 2026·5 min read·7 visits

PoC Available

Executive Summary (TL;DR)

Wasmtime hosts crash if a guest adds more than 32,768 HTTP headers. This exploits a hard limit in the underlying Rust `http` crate, causing an uncatchable panic. Fix requires upgrading to versions 24.0.6+, 36.0.6+, 40.0.4+, 41.0.4+, or 42.0.0.

A Denial of Service vulnerability in Wasmtime's wasi-http implementation allows a malicious guest module to crash the host runtime. By exploiting an internal limit in Rust's http crate, an attacker can trigger a host-side panic, bypassing the sandbox's exception handling and taking down the entire process.

The Hook: The Sandbox That Couldn't Count

WebAssembly (Wasm) is sold on the promise of the perfect sandbox. You run untrusted code, and if that code goes rogue, it traps. The guest dies, but the host—and your server—stays alive. It's the core contract of serverless computing and edge workers. But CVE-2026-27572 is a reminder that even the sturdiest sandboxes are built on top of libraries that have their own opinions about reality.

In this case, the opinion belongs to the Rust http crate, a fundamental building block for Rust web services. It turns out that Wasmtime, one of the most popular Wasm runtimes, blindly trusted this crate to handle HTTP headers for the wasi-http interface. They forgot one tiny detail: the http crate has a hard, panic-inducing limit on how many headers you can stuff into a map.

This isn't a complex buffer overflow or a use-after-free. This is a logic bomb. A malicious guest simply says, "Here is a header," 32,769 times. The host tries to comply, hits the internal limit, and instead of politely declining, it screams and dies. Process terminated. Service down.

The Flaw: 15 Bits to Doomsday

To understand why this crashes, we have to look at the http crate's HeaderMap implementation. To save memory and optimize cache locality, HeaderMap doesn't just use a standard vector or hash map. It uses a specialized structure where indices are stored in 15 bits.

Mathematically, $2^{15}$ is 32,768. That is the hard ceiling. The developers of the http crate made a conscious decision: if you try to insert the 32,769th header, the program is in an invalid state, and the safe thing to do is panic!(). In a standard Rust application, this might be acceptable—you shouldn't be processing requests with that many headers anyway.

But Wasmtime isn't a standard application; it's a host for untrusted code. When the Wasm guest calls the WASI function to append a header, Wasmtime executes that call on the host side.

> [!CAUTION] > Because the panic happens in host code (Rust) and not inside the Wasm linear memory, the Wasm sandbox cannot contain it. The panic unwinds the host stack, killing the Wasmtime process instantly.

It’s the digital equivalent of a passenger in a taxi pressing a button that detonates the car. The driver (host) should have locked that button, but they didn't.

The Code: Rust Panics and Wrapper Fixes

The fix involves wrapping the volatile HeaderMap in a new structure that counts before it leaps. The patch introduces FieldMap (and FieldMapInner), which tracks resource usage explicitly.

Before the fix, the code likely looked something like this (simplified):

// Vulnerable: Blindly delegating to http::HeaderMap
fn append(&mut self, name: String, value: Vec<u8>) -> Result<(), Error> {
    // If this pushes count > 32768, header_map panics!
    self.header_map.append(name, value);
    Ok(())
}

The fix, found in commit 301dc7162cca51def19131019af1187f45901c0a, introduces a check. Instead of letting HeaderMap enforce the limit via panic, Wasmtime now enforces a limit (configurable via max_http_fields_size) and returns a trap if breached.

// Fixed: Check bounds or trap
fn append(&mut self, name: String, value: Vec<u8>) -> Result<(), Error> {
    // 1. Calculate size cost
    let extra_size = name.len() + value.len();
    
    // 2. Check against configurable limit (and the hard 32k limit)
    if self.count + 1 > 32768 || 
       self.size + extra_size > self.max_http_fields_size {
        // 3. Return a specific error that traps the GUEST, not the HOST
        return Err(Error::trap("header count exceeded"));
    }
    
    self.header_map.append(name, value);
    self.count += 1;
    Ok(())
}

This transforms an uncontrolled host crash into a controlled guest termination. The bad actor gets kicked out, and the server keeps running.

The Exploit: Death by Iteration

Exploiting this is trivially easy for anyone who can upload a Wasm module to a vulnerable target. You don't need shellcode. You don't need to bypass ASLR. You just need a loop.

The attack vector relies on the wasi:http/types interface. A guest module would look something like this in Rust-compiled-to-Wasm:

// Malicious Guest Code
use wasi::http::types::{Fields, OutgoingBody};
 
fn main() {
    let fields = Fields::new();
    let key = "X-Pwn-Count";
    let value = "1".as_bytes();
 
    // The magic number is 32,768. We go one higher.
    for i in 0..33_000 {
        // This hostcall eventually triggers the panic
        fields.append(key, value).unwrap();
    }
}

When i hits 32,769, the host enters the HeaderMap::append function, hits the assertion, and the entire Wasmtime runtime vanishes from the process list. In a serverless environment (like a FaaS provider using Wasmtime), this could mean taking down the worker node responsible for handling hundreds of other innocent requests.

The Mitigation: Putting a Lid on It

The primary fix is upgrading Wasmtime. The team released patches across all supported major versions. If you are running wasmtime as a library, check your Cargo.toml. If you are running the CLI, check your binary version.

However, the patch does more than just stop the panic; it introduces Knobs. Security controls are useless if you can't tune them. The fix adds Config::max_wasm_http_fields_size, allowing embedders to define exactly how much memory a guest's HTTP headers can consume.

If you cannot patch immediately (why?), your only option is to disable the wasi-http capability entirely for untrusted modules. There is no firewall rule that can count the internal elements of a Rust struct inside a binary protocol.

Official Patches

Bytecode AllianceCommit fixing the resource limit issue
GitHub AdvisoryOfficial Advisory

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 < 24.0.6Wasmtime Runtime 25.x < 36.0.6Wasmtime Runtime 37.x < 40.0.4Wasmtime Runtime 41.0.0 - 41.0.3Any application embedding Wasmtime with WASI-HTTP enabled

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
Vulnerability IDCVE-2026-27572
CWE IDCWE-770
Attack VectorNetwork (Guest-to-Host)
CVSS Score6.9 (Medium)
ImpactDenial of Service (Process Crash)
Componentwasmtime-wasi-http
PlatformRust / WebAssembly

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
CWE-770
Allocation of Resources Without Limits or Throttling

Allocation of Resources Without Limits or Throttling

Known Exploits & Detection

Internal AnalysisGuest module looping over fields.append until host panic.

Vulnerability Timeline

Initial development of fix in private branches
2026-01-05
GHSA-243v-98vx-264h Published
2026-02-24
Patched versions released
2026-02-24

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.