Feb 28, 2026·6 min read·9 visits
MessagePack for Java versions before 0.9.11 contain a denial-of-service vulnerability. Attackers can trigger an immediate JVM crash by sending a tiny packet that declares a massive payload size, causing the library to attempt an impossible memory allocation.
A critical resource exhaustion vulnerability exists in the MessagePack for Java (msgpack-java) library, specifically within its deserialization logic for binary and extended data types. The flaw stems from an uncontrolled memory allocation pattern where the library attempts to allocate heap memory based on a declared length field in the input stream before verifying if sufficient data exists. This allows remote attackers to trigger an `OutOfMemoryError` (OOM) and crash the Java Virtual Machine (JVM) by sending a specially crafted 'MessagePack Bomb'—a payload as small as 6 bytes that declares a 2GB size.
MessagePack is a binary serialization format designed for efficiency and speed, often used as a replacement for JSON in high-performance microservices and data pipelines. The vulnerability, CVE-2026-21452, impacts the msgpack-java library's handling of large binary data types (BIN32) and extension types (EXT32). These formats include a 4-byte length header indicating the size of the subsequent payload.
The core issue lies in the library's eager allocation strategy. When the deserializer encounters a header declaring a large payload (e.g., 2 GB), it immediately allocates a byte array of that size on the JVM heap. This allocation occurs before the library attempts to read the actual payload bytes from the network stream. Consequently, an attacker does not need to send 2 GB of traffic to consume 2 GB of memory on the target server. They simply need to send the header declaring that size.
This creates an asymmetric denial-of-service condition. A packet smaller than 10 bytes can force the server to allocate gigabytes of memory. If the allocation request exceeds the available heap space, the JVM throws a java.lang.OutOfMemoryError, typically causing the application container or the entire service process to terminate abruptly.
The vulnerability is a classic instance of CWE-789: Memory Allocation with Excessive Size Value. It resides in the MessageUnpacker class, specifically in the methods responsible for reading payload bodies, such as readPayload(int length). In vulnerable versions, the logic blindly trusts the length integer extracted from the MessagePack header.
When unpackValue() or readPayload() is called for a BIN32 or EXT32 type, the code performs the following sequence:
0xC6 for BIN32) and the subsequent 4-byte length integer.new byte[length]. If length is Integer.MAX_VALUE (approx. 2.14 GB), the JVM attempts to find a contiguous block of heap memory of that size.This sequence is flawed because it lacks a "check-then-act" mechanism. It acts (allocates) based on untrusted input before verifying that the input stream actually contains the claimed amount of data. This violates the principle that resources should only be allocated proportional to the data actually received or validated.
The flaw is particularly dangerous because msgpack-java is often used in public-facing APIs and high-throughput data ingestion services where untrusted input is common. The lack of an upper bound check or a stream-availability check makes this trivial to exploit.
The remediation involves shifting from an eager allocation strategy to a gradual allocation strategy for large payloads. The fix was implemented in commit daa2ea6b2f11f500e22c70a22f689f7a9debdeae.
The original implementation optimized for speed by allocating the buffer in one operation. This is efficient for trusted data but catastrophic for untrusted input.
// org.msgpack.core.MessageUnpacker
public byte[] readPayload(int length) throws IOException {
// DANGER: Unconditional allocation based on untrusted 'length'
byte[] newArray = new byte[length];
readPayload(newArray);
return newArray;
}The fix introduces a threshold (GRADUAL_ALLOCATION_THRESHOLD, set to 64 MB). Payloads smaller than this threshold are still allocated eagerly to maintain performance. Payloads larger than the threshold are allocated gradually as data is read from the stream.
// org.msgpack.core.MessageUnpacker
private static final int GRADUAL_ALLOCATION_THRESHOLD = 64 * 1024 * 1024; // 64MB
public byte[] readPayload(int length) throws IOException {
if (length < 0) {
throw new MessageSizeException("Invalid payload size: " + length, length);
}
// FIX: If length is massive, use gradual allocation to prevent OOM bombs
if (length > GRADUAL_ALLOCATION_THRESHOLD) {
return readPayloadGradually(length);
}
// Fast path for small payloads
byte[] newArray = new byte[length];
readPayload(newArray);
return newArray;
}
private byte[] readPayloadGradually(int length) throws IOException {
byte[] buffer = new byte[length];
int totalRead = 0;
while (totalRead < length) {
// Read in chunks (e.g., 8KB or available bytes)
// If EOF is reached before 'length' is met, throw exception
// preventing the full allocation if data is missing.
// ... implementation details ...
}
return buffer;
}By reading gradually, the system ensures that memory is only consumed if the attacker actually transmits the data. This neutralizes the "MessagePack Bomb" because sending 2 GB of actual data is a network bandwidth attack, not a protocol logic exploit, and is handled by standard timeouts and rate limits.
Exploiting CVE-2026-21452 requires sending a malformed MessagePack structure to a vulnerable endpoint. The attack does not require authentication or complex chaining. The attacker simply acts as a client submitting data.
The payload relies on the BIN32 (Binary 32-bit) format code 0xC6 or EXT32 (Extension 32-bit) format code 0xC9.
0xC6.0x7F 0xFF 0xFF 0xFF (Maximum signed 32-bit integer, ~2.14 GB).C6 7F FF FF FF.If the server has a large heap (e.g., 8 GB) and does not crash immediately, the attack still degrades performance significantly. The thread handling the request holds a 2 GB array alive, triggering massive Garbage Collection (GC) pauses. Multiple concurrent requests of this type will quickly exhaust even the largest heaps.
The primary impact of this vulnerability is Denial of Service (DoS). The severity is High (CVSS 7.5) because it can be exploited remotely by an unauthenticated attacker with minimal resources.
OutOfMemoryError is an Error type in Java, not an Exception. It is often unrecoverable at the request level and frequently causes the JVM to terminate or enter a zombie state where it cannot process new requests.This vulnerability does not lead to:
The scope is strictly limited to availability, but for critical infrastructure or high-availability APIs, the loss of availability is a catastrophic failure mode.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
msgpack-java MessagePack | < 0.9.11 | 0.9.11 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-789 |
| CVSS v3.1 | 7.5 (High) |
| Attack Vector | Network |
| Impact | Availability (DoS) |
| Exploit Status | PoC Available |
| Fix Version | 0.9.11 |
The product allocates memory based on an untrusted size value, but it does not verify that the size is within expected limits or that the data is actually available, allowing an attacker to cause resource exhaustion.