Wasmi's Linear Memory has a Critical Use After Free Vulnerability
Description
Wasmi is a WebAssembly interpreter focused on constrained and embedded systems. In versions 0.41.0, 0.41.1, 0.42.0 through 0.47.1, 0.50.0 through 0.51.2 and 1.0.0, Wasmi's linear memory implementation leads to a Use After Free vulnerability, triggered by a WebAssembly module under certain memory growth conditions. This issue potentially leads to memory corruption, information disclosure, or code execution. This issue is fixed in versions 0.41.2, 0.47.1, 0.51.3 and 1.0.1. To workaround this issue, consider limiting the maximum linear memory sizes where feasible.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A use-after-free vulnerability in Wasmi's linear memory implementation allows memory corruption, information disclosure, or code execution via crafted WebAssembly modules.
Vulnerability
A use-after-free vulnerability exists in Wasmi, a WebAssembly interpreter focused on constrained and embedded systems, affecting versions 0.41.0 to 1.0.0 [1][4]. The bug resides in the ByteBuffer::grow method of Wasmi's linear memory implementation. When memory growth occurs, the get_vec function returns a Vec that, upon being dropped, frees the underlying buffer, while the ByteBuffer still holds pointers to the freed memory, leading to a use-after-free condition [3].
Exploitation
An attacker can trigger this vulnerability by supplying a specially crafting a WebAssembly module that causes specific memory growth operations [1][4]. No authentication is required, as the module can be loaded by any application using the vulnerable Wasmi interpreter. The attack surface is limited to systems running Wasmi versions in the affected range, which includes many embedded and constrained environments where Wasmi is used.
Impact
Successful exploitation can lead to memory corruption, information disclosure, or arbitrary code execution [1][4]. The advisory rates the impact as high across confidentiality, integrity, and availability, as an attacker could read arbitrary memory, corrupt memory for further attacks, or crash the interpreter [4].
Mitigation
Patches are available in Wasmi versions 0.41.2, 0.47.1, 0.51.3, and 1.0.1 [1][4]. The fix involves wrapping the Vec in ManuallyDrop to prevent premature deallocation [3]. As a workaround, limiting maximum linear memory sizes can reduce exposure where patching is not immediately feasible [1][4].
AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
wasmicrates.io | >= 0.41.0, < 0.41.2 | 0.41.2 |
wasmicrates.io | >= 0.42.0, < 0.47.1 | 0.47.1 |
wasmicrates.io | >= 0.50.0, < 0.51.3 | 0.51.3 |
wasmicrates.io | >= 1.0.0, < 1.0.1 | 1.0.1 |
Affected products
2- wasmi-labs/wasmiv5Range: >= 0.41.0, < 0.41.2
Patches
10e6f0d2a8325fix bug in ByteBuffer::grow
1 file changed · +14 −5
crates/core/src/memory/buffer.rs+14 −5 modified@@ -130,14 +130,18 @@ impl ByteBuffer { } /// Grow the byte buffer to the given `new_size` when backed by a [`Vec`]. - fn grow_vec(&mut self, mut vec: Vec<u8>, new_size: usize) -> Result<(), MemoryError> { + fn grow_vec( + &mut self, + mut vec: ManuallyDrop<Vec<u8>>, + new_size: usize, + ) -> Result<(), MemoryError> { debug_assert!(vec.len() <= new_size); let additional = new_size - vec.len(); if vec.try_reserve(additional).is_err() { return Err(MemoryError::OutOfSystemMemory); }; vec.resize(new_size, 0x00_u8); - (self.ptr, self.len, self.capacity) = vec_into_raw_parts(vec); + (self.ptr, self.len, self.capacity) = vec_into_raw_parts(ManuallyDrop::into_inner(vec)); Ok(()) } @@ -181,16 +185,21 @@ impl ByteBuffer { /// /// # Note /// - /// The returned `Vec` will free its memory and thus the memory of the [`ByteBuffer`] if dropped. - fn get_vec(&mut self) -> Option<Vec<u8>> { + /// - The returned `Vec` will free its memory and thus the memory of the [`ByteBuffer`] if dropped. + /// - The returned `Vec` is returned as [`ManuallyDrop`] to prevent its buffer from being freed + /// automatically upon going out of scope. + fn get_vec(&mut self) -> Option<ManuallyDrop<Vec<u8>>> { if self.is_static { return None; } // Safety // // - At this point we are guaranteed that the byte buffer is backed by a `Vec` // so it is safe to reconstruct the `Vec` by its raw parts. - Some(unsafe { Vec::from_raw_parts(self.ptr, self.len, self.capacity) }) + // - The returned `Vec` is returned as [`ManuallyDrop`] to prevent its buffer from being free + // upon going out of scope. + let vec = unsafe { Vec::from_raw_parts(self.ptr, self.len, self.capacity) }; + Some(ManuallyDrop::new(vec)) } }
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/advisories/GHSA-g4v2-cjqp-rfmqghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-66627ghsaADVISORY
- github.com/wasmi-labs/wasmi/commit/0e6f0d2a8325602c58d6a53ce1c0e6045eb6a490ghsaWEB
- github.com/wasmi-labs/wasmi/security/advisories/GHSA-g4v2-cjqp-rfmqghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.