CVE-2022-39394 is a vulnerability that quietly lurked in Wasmtime, a popular standalone WebAssembly runtime, up until version 2..2. This post will walk you through what was vulnerable, how it happened in code, why it matters, and how to protect yourself. If you work with Wasmtime’s C API, this is essential reading.

What Is Wasmtime?

Wasmtime lets you run WebAssembly (Wasm) modules outside of the browser, using a runtime built in Rust. You can interact with Wasmtime from several programming languages, including C with an official C API.

What Went Wrong: The Trap Code Mishap

Before version 2..2, the function wasmtime_trap_code had a fatal mismatch between the function's *implementation* in code and its *declaration* in Wasmtime’s C header file. They were not using the same type or size for an important argument.

In simple terms:  
- The header file (wasmtime/trap.h) told users that the function expected a pointer to a 1-byte buffer.

Here’s a simplified version of what the header declared

// from wasmtime/trap.h
bool wasmtime_trap_code(const wasmtime_trap_t *trap, uint8_t *code);


It suggests you should provide a 1-byte-wide uint8_t buffer to get the trap code.

The Flawed Implementation

But deep inside the actual Wasmtime code, the implementation wrote a 4-byte value (uint32_t) into the space pointed to by code:

// simplified, pseudocode version of implementation
bool wasmtime_trap_code(const wasmtime_trap_t *trap, uint8_t *code) {
    // ...some logic...
    *(uint32_t*)code = some_trap_code; // writes FOUR bytes!
    // ...more logic...
    return true;
}


If you passed in a buffer sized for 1 byte as the official docs suggested, 3 extra bytes would be overwritten next to it!

Exploit Details: What Could Happen?

Because this is a write-where-overflow bug, it can smash up to 3 bytes beyond your buffer boundary. The specific effect depends on your memory layout, but here’s why it’s risky:

- Memory Corruption: The extra bytes could overwrite other stack or heap data, causing mysterious bugs or security holes.
- Denial of Service: In worst cases, your program might crash (segfault) if the overwritten bytes are important.
- Potential Exploitation: While it’s unlikely to be trivially exploitable for code execution, such bugs have been used in the past as stepping stones in more complex attacks.

Here’s a code snippet to illustrate the hazard

#include <stdio.h>
#include <stdint.h>
#include <string.h>

// Simulated vulnerable function
void wasmtime_trap_code(const void *trap, uint8_t *code) {
    *(uint32_t *)code = xDEADBEEF;  // writes 4 bytes, not 1!
}

int main() {
    uint8_t code_buf[1];           // only 1 byte allocated
    memset(code_buf, , 4);        // clear 4 bytes for demo
    wasmtime_trap_code(NULL, code_buf);  

    printf("code: %02X\n", code_buf[]);
    printf("overflow: %02X %02X %02X\n", code_buf[1], code_buf[2], code_buf[3]);
    return ;
}

Output (unsafe!)

code: EF
overflow: BE AD DE


Here, you see that the three extra bytes next to your buffer get trashed.

If you call the C API wasmtime_trap_code, you *are affected* if your buffer is only 1 byte.

- Most users who only used documented code examples from Wasmtime’s early guides would have had this bug in existing code.

How Was This Fixed?

The bug was patched in Wasmtime 2..2. The fix corrected the function signature and/or implementation so the buffer sizes match.

Reference:  
- GitHub advisory  
- CVE Details

If you must use an older release, allocate a 4-byte buffer and cast it to a 1-byte buffer

uint32_t code_buf_wide = ;
// Unsafe cast, but successful with old versions
wasmtime_trap_code(trap, (uint8_t*)&code_buf_wide);
// Now only look at the first byte if that's what you expect


This prevents overwriting adjacent memory. But the *best* fix is to upgrade to Wasmtime 2..2 or newer.

Lessons from CVE-2022-39394

- Always make sure your function declarations and implementations match, especially across FFI/C APIs.

Never trust a library to only write what you expect; defensive coding saves time and pain.

- Buffer overflows aren’t just “C problems”—they still happen, even in modern, memory-safe codebases when the lowest layers break trust.

Conclusion

CVE-2022-39394 was a classic C-language pitfall—a type mismatch that left many projects vulnerable to subtle overflows. While it was quickly patched, any user of Wasmtime’s C API should double-check their dependency versions and code. If in doubt: update now!


Original references:  
- Wasmtime Security Advisory GHSA-4x29-m48j-8p6f  
- Wasmtime v2..2 Release Notes  
- CVE-2022-39394 at NVD

Timeline

Published on: 11/10/2022 20:15:00 UTC
Last modified on: 11/16/2022 13:31:00 UTC