GHSA-7qmx-3fpx-r45m CVE-2024-47813 PYSEC-2024-311 RUSTSEC-2024-0439
Wasmtime race condition could lead to WebAssembly control-flow integrity and type safety violations
- Severity
- 0.0 / 10
- Low · CVSS 4.0
- Exploit chance (EPSS)
- 0.15%
- Chance of exploitation in the next 30 days. Higher than 4.41% of scored vulnerabilities.
- Known exploited
- No
- Not in CISA's catalog
- Weakness
- CWE-367 Time-of-check Time-of-use (TOCTOU) Race Condition
- Fix
21.0.2- Upgrade wasmtime to this version or later
Description
Impact
Under certain concurrent event orderings, a wasmtime::Engine's internal type registry was susceptible to double-unregistration bugs due to a race condition, leading to panics and potentially type registry corruption. That registry corruption could, following an additional and particular sequence of concurrent events, lead to violations of WebAssembly's control-flow integrity (CFI) and type safety. Users that do not use wasmtime::Engine across multiple threads are not affected. Users that only create new modules across threads over time are additionally not affected.
Reproducing this bug requires creating and dropping multiple type instances (such as wasmtime::FuncType or wasmtime::ArrayType) concurrently on multiple threads, where all types are associated with the same wasmtime::Engine. Wasm guests cannot trigger this bug. See the "References" section below for a list of Wasmtime types-related APIs that are affected.
Wasmtime maintains an internal registry of types within a wasmtime::Engine and an engine is shareable across threads. Types can be created and referenced through creation of a wasmtime::Module, creation of wasmtime::FuncType, or a number of other APIs where the host creates a function (see "References" below). Each of these cases interacts with an engine to deduplicate type information and manage type indices that are used to implement type checks in WebAssembly's call_indirect function, for example. This bug is a race condition in this management where the internal type registry could be corrupted to trigger an assert or contain invalid state.
Wasmtime's internal representation of a type has individual types (e.g. one-per-host-function) maintain a registration count of how many time it's been used. Types additionally have state within an engine behind a read-write lock such as lookup/deduplication information. The race here is a time-of-check versus time-of-use (TOCTOU) bug where one thread atomically decrements a type entry's registration count, observes zero registrations, and then acquires a lock in order to unregister that entry. However, between when this first thread observed the zero-registration count and when it acquires that lock, another thread could perform the following sequence of events: re-register another copy of the type, which deduplicates to that same entry, resurrecting it and incrementing its registration count; then drop the type and decrement its registration count; observe that the registration count is now zero; acquire the type registry lock; and finally unregister the type. Now, when the original thread finally acquires the lock and unregisters the entry, it is the second time this entry has been unregistered.
| Thread A | Thread B |
|---|---|
acquire(type registry lock) |
|
decref(E) --> 0 |
|
block_on(type registry lock) |
|
register(E') == incref(E) --> 1 |
|
release(type registry lock) |
|
decref(E) --> 0 |
|
acquire(type registry lock) |
|
unregister(E) |
|
release(type registry lock) |
|
acquire(type registry lock) |
|
unregister(E) |
This double-unregistration could then lead to a WebAssembly CFI violation under the following conditions: a new WebAssembly module X was loaded into the engine before the second, buggy unregistration occurs; X defined a function type F that was allocated in the same type registry slot where the original entry was allocated; the second, buggy unregistration incorrectly unregistered F; another new WebAssembly module Y was loaded into the engine; Y defined a function type G, different from F, but which is also allocated in the same type registry slot; a funcref of type G is created, either by the host or by Wasm; that funcref is passed to a WebAssembly instance of module X; that instance performs a call_indirect to that funcref; the call_indirect's dynamic type check, which preserves CFI, could incorrectly pass in this case, because F and G were assigned the same type registry slot. This would, ultimately, allow calling a function with too many, too few, or wrongly-typed arguments, violating CFI and type safety.
We were not able to reproduce this CFI violation in a vanilla Wasmtime build, although it remains theoretically possible. However, by modifying Wasmtime's source code to make losing the races described above more likely (by disabling certain assertions, inserting panic catches, and adding retry loops in a few places if we did not lose the race) we were able to incorrectly get a funcref to pass a type check that it should have failed, which would allow the CFI violation.
Patches
This bug was originally introduced in Wasmtime 19's development of the WebAssembly GC proposal. This bug affects users who are not using the GC proposal, however, and affects Wasmtime in its default configuration even when the GC proposal is disabled. Wasmtime users using 19.0.0 and after are all affected by this issue. We have released the following Wasmtime versions, all of which have a fix for this bug:
- 21.0.2
- 22.0.1
- 23.0.3
- 24.0.1
- 25.0.2
Workarounds
If your application creates and drops Wasmtime types on multiple threads concurrently, there are no known workarounds. Users are encouraged to upgrade to a patched release.
References
The following APIs create or drop types, and therefore are affected by this race condition if performed on multiple threads concurrently and are all associated with the same wasmtime::Engine:
wasmtime::FuncType::new- Also reachable from creation of
wasmtime::Func - Also reachable from
wasmtime::Linker::func_*
- Also reachable from creation of
wasmtime::ArrayType::newwasmtime::StructType::newwasmtime::Func::tywasmtime::Global::tywasmtime::Table::tywasmtime::Extern::tywasmtime::Export::tywasmtime::UnknownImportError::tywasmtime::ImportType::tywasmtime::ExportType::tywasmtime::Val::tywasmtime::Ref::tywasmtime::AnyRef::tywasmtime::EqRef::tywasmtime::ArrayRef::tywasmtime::StructRef::ty- Dropping a
wasmtime::FuncType - Dropping a
wasmtime::ArrayType - Dropping a
wasmtime::StructType - Dropping a
wasmtime::ExternType - Dropping a
wasmtime::GlobalType - Dropping a
wasmtime::TableType - Dropping a
wasmtime::ValType - Dropping a
wasmtime::RefType - Dropping a
wasmtime::HeapType - Dropping a
wasmtime::UnknownImportError - Dropping a
wasmtime::Linker
The change which introduced this bug was #7969
Affected versions
PyPI
| Package | Vulnerable | Fixed in |
|---|---|---|
| wasmtime | <= 19.0.0<= 19.0.1<= 19.0.2<= 20.0.0<= 20.0.1<= 20.0.2<= 21.0.0<= 21.0.1<= 22.0.0<= 23.0.0<= 23.0.1<= 23.0.2<= 24.0.0<= 25.0.0<= 25.0.1 |
No fix yet |
crates.io
| Package | Vulnerable | Fixed in |
|---|---|---|
| wasmtime | >= 19.0.0, < 21.0.2 |
21.0.2 |
| wasmtime | >= 22.0.0, < 22.0.1 |
22.0.1 |
| wasmtime | >= 23.0.0, < 23.0.3 |
23.0.3 |
| wasmtime | >= 24.0.0, < 24.0.1 |
24.0.1 |
| wasmtime | >= 25.0.0, < 25.0.2 |
25.0.2 |
| wasmtime | >= 19.0.0, < 21.0.2>= 22.0.0, < 22.0.1>= 23.0.0, < 23.0.3>= 24.0.0, < 24.0.1>= 25.0.0, < 25.0.2 |
21.0.222.0.123.0.324.0.125.0.2 |
How to fix
Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.
wasmtime crates.io → 21.0.2
- cargo
cargo update -p wasmtime --precise 21.0.2
Severity breakdown
CVSS 4.0 0.0
CVSS:4.0/AV:L/AC:L/AT:P/PR:H/UI:A/VC:N/VI:L/VA:L/SC:N/SI:N/SA:N
- Attack vector
- Local
- Attack complexity
- Low
- Attack requirements
- Present
- Privileges required
- High
- User interaction
- Active
- Confidentiality (vulnerable system)
- None
- Integrity (vulnerable system)
- Low
- Availability (vulnerable system)
- Low
- Confidentiality (subsequent systems)
- None
- Integrity (subsequent systems)
- None
- Availability (subsequent systems)
- None
CVSS 3.1 2.9
CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:U/C:N/I:L/A:L
- Attack vector
- Local
- Attack complexity
- High
- Privileges required
- High
- User interaction
- Required
- Scope
- Unchanged
- Confidentiality
- None
- Integrity
- Low
- Availability
- Low
Weakness
CWE-367: Time-of-check Time-of-use (TOCTOU) Race Condition
The product checks the state of a resource before using that resource, but the resource's state can change between the check and the use in a way that invalidates the results of the check.
How to prevent it
- Implementation: The most basic advice for TOCTOU vulnerabilities is to not perform a check before the use. This does not resolve the underlying issue of the execution of a function on a resource whose state and identity cannot be assured, but it does help to limit the false sense of security given by the check.
- Implementation: When the file being altered is owned by the current user and group, set the effective gid and uid to that of the current user and group when executing this statement.
- Architecture and Design: Limit the interleaving of operations on files from multiple processes.
- Implementation, Architecture and Design: If you cannot perform operations atomically and you must share access to the resource between multiple processes or threads, then try to limit the amount of time (CPU cycles) between the check and use of the resource. This will not fix the problem, but it could make it more difficult for an attack to succeed.
- Implementation: Recheck the resource after the use call to verify that the action was taken appropriately.
- Architecture and Design: Ensure that some environmental locking mechanism can be used to protect resources effectively.
- Implementation: Ensure that locking occurs before the check, as opposed to afterwards, such that the resource, as checked, is the same as it is when in use.
References
Advisories
Packages
Other links
- github.com/bytecodealliance/wasmtime/security/advisories/GHSA-7qmx-3fpx-r45m
- github.com/bytecodealliance/wasmtime/pull/7969
- github.com/bytecodealliance/wasmtime/commit/0ebe54d05f0e1f6c64b7c8bb48c9e9f6c95…
- github.com/pypa/advisory-database/tree/main/vulns/wasmtime/PYSEC-2024-311.yaml
- rustsec.org/advisories/RUSTSEC-2024-0439.html
Timeline
- Published
- Last updated by the source
- Latest EPSS score
Related advisories
| Advisory | Severity | Why it's related |
|---|---|---|
| RUSTSEC-2026-0424 Unchecked memory usage in transferring borrowed resources between components | Not rated yet | Also affects wasmtime |
| RUSTSEC-2026-0423 Cross-engine type confusion with host-created struct-types-with-supertypes | Not rated yet | Also affects wasmtime |
| RUSTSEC-2026-0422 Typed functions with `i31` or `nullref` arguments may panic due to insufficient type-check | Low | Also affects wasmtime |
| RUSTSEC-2026-0379 Wasmtime: Cranelift backend on aarch64 can jump to incorrect target on large Wasm `br_table` instruction | Critical | Also affects wasmtime |
| GHSA-9pvw-hwfg-92h5 Wasmtime: Panic lowering a host-created component model stream into a guest that expects a different payload type | Medium | Also affects wasmtime |
| GHSA-897f-g5gm-fmxm Wasmtime: Bit-packing in Cranelift compiler causes silent overflow and miscompilation | Critical | Also affects wasmtime |
| RUSTSEC-2026-0364 Exception tags can cause host data structures to be unaligned | Not rated yet | Also affects wasmtime |
| RUSTSEC-2026-0363 Component-model handle tables are capped only per instance and charged to no limit | Medium | Also affects wasmtime |
MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.
Check your repos with MergeHarbor