Логотип exploitDog
Консоль
Логотип exploitDog

exploitDog

github логотип

GHSA-p35w-6mx2-q4pc

Опубликовано: 23 июл. 2026
Источник: github
Github: Не прошло ревью
CVSS4: 5.3

Описание

AMQP 1.0 symbolic body descriptor prefix collisions bypass validation

Summary

RabbitMQ's optimized AMQP 1.0 server_mode parser recognizes symbolic message body descriptors by matching a fixed textual prefix but ignores the encoded symbol length. A remote AMQP 1.0 publisher can therefore submit a described value whose descriptor merely begins with amqp:data:binary, amqp:amqp-sequence:list, or amqp:amqp-value:*, and RabbitMQ classifies it as the corresponding standard body section.

The primary proof uses the well-formed but unknown descriptor amqp:data:binary@. Structurally inconsistent encodings with truncated or overlong declared lengths reach the same fast path as long as the fixed prefix is physically present. These cases should be distinguished: the primary sample is a valid generic AMQP described value, while some other affected lengths produce malformed encodings.

The accepted bytes are retained through classic, quorum, and stream queues and are forwarded unchanged to AMQP 1.0 consumers. RabbitMQ's normal decoder rejects the unknown descriptor. For a body misclassified as data, RabbitMQ also performs a full decode during conversion to AMQP 0-9-1 and other protocols, causing an uncontrolled parser exit in the consumer protocol process.

This is best characterized as a body-descriptor classification bypass with protocol-specific stored poison-message impact. It does not provide a routing or authorization bypass, and it is not a classic message-smuggling primitive.

Affected revision

Confirmed against:

f02b3c6b52529d6809c56c2516f3dc4333605688

Confirmed with Erlang/OTP 27.

The affected release range has not been established. This report only claims the revision above.

Affected components

  • deps/amqp10_common/src/amqp10_binary_parser.erl
  • deps/rabbit/src/mc_amqp.erl
  • AMQP 1.0 publishing
  • AMQP 1.0 normal-mode consuming
  • AMQP 1.0 to AMQP 0-9-1 and other cross-protocol conversion paths

Attack requirements

  • The attacker can authenticate to RabbitMQ over AMQP 1.0
  • The attacker has write permission to a target exchange or queue
  • A victim consumes the stored entry using a strict AMQP 1.0 decoder or a protocol path that forces full AMQP body decoding

The attacker does not need control of the RabbitMQ node, the victim process, or the transport between RabbitMQ and the victim.

Root cause

The symbolic body fast paths bind the symbol length to _S but do not compare it with the fixed descriptor length:

pm(<<?DESCRIBED, ?CODE_SYM_8, _S:8, "amqp:data:binary", _Rest/binary>>, true, B) -> reached_body(B, ?DESCRIPTOR_CODE_DATA); pm(<<?DESCRIBED, ?CODE_SYM_8, _S:8, "amqp:amqp-sequence:list", _Rest/binary>>, true, B) -> reached_body(B, ?DESCRIPTOR_CODE_AMQP_SEQUENCE); pm(<<?DESCRIBED, ?CODE_SYM_8, _S:8, "amqp:amqp-value:*", _Rest/binary>>, true, B) -> reached_body(B, ?DESCRIPTOR_CODE_AMQP_VALUE);

Equivalent vulnerable clauses exist for sym32.

The valid lengths are:

  • amqp:data:binary: 16
  • amqp:amqp-sequence:list: 23
  • amqp:amqp-value:*: 17

reached_body/2 returns immediately at the section start without consuming or validating the descriptor or its value:

reached_body(Position, DescriptorCode) -> [{{pos, Position}, {body, DescriptorCode}}].

The affected ranges are therefore:

  • sym8 data: every value except 16
  • sym8 sequence: every value except 23
  • sym8 value: every value except 17
  • sym32 data: every value except 16
  • sym32 sequence: every value except 23
  • sym32 value: every value except 17

The parser does not require the declared number of symbol bytes to exist. The fixed textual prefix only needs to be physically present in the transfer payload.

Lengths other than the exact registered descriptor length are not semantically equivalent. A longer, fully present symbol can be a well-formed unknown descriptor with a colliding prefix. A shorter or unfulfilled declared length can instead make the generic AMQP value structurally inconsistent.

Parser differential

This well-formed generic AMQP described value:

00 a3 11 61 6d 71 70 3a 64 61 74 61 3a 62 69 6e 61 72 79 40 a0 03 61 62 63

Decoded fields:

00 described type a3 11 sym8 with declared length 17 61..79 40 "amqp:data:binary" plus "@" a0 03 61 62 63 binary value "abc"

RabbitMQ server_mode interpretation:

[{{pos, 0}, {body, 16#75}}]

Normal parser interpretation:

{described, {symbol, <<"amqp:data:binary@">>}, {binary, <<"abc">>}}

The normal framing decoder then exits because the well-formed descriptor <<"amqp:data:binary@">> is not registered as an AMQP message section.

Inbound and storage path

The AMQP reader parses the transfer performative and passes the remaining payload to the session as opaque message bytes.

rabbit_amqp_session:incoming_link_transfer/4 calls:

mc:init(mc_amqp, PayloadBin, #{})

mc_amqp:init/1 invokes:

amqp10_framing:decode_bin(Payload, [server_mode])

The returned body marker is used by msg_body_encoded/3 to retain the original bare message:

msg_body_encoded([{{pos, Pos}, {body, Code}}], Payload, Msg) when is_binary(Payload) -> Bin = binary_part_bare_and_footer(Payload, Pos), Msg#msg_body_encoded{ bare_and_footer = Bin, bare_and_footer_body_pos = 0, body_code = Code }.

mc_amqp:prepare(store, ...) changes only the record representation. The bare_and_footer binary is not normalized or reparsed.

AMQP 1.0 delivery similarly appends bare_and_footer unchanged to the outgoing transfer payload.

Cross-protocol failure

For bodies classified as data, mc_amqp:msg_to_sections/1 performs a full decode before converting to another protocol:

BodyAndFooter = case BodyCode of ?DESCRIPTOR_CODE_DATA -> amqp10_framing:decode_bin(BodyAndFooterBin); _ -> [{amqp_encoded_body_and_footer, BodyAndFooterBin}] end.

The colliding descriptor reaches amqp10_framing0:record_for/1, which exits because it is unknown.

This conversion path is used by AMQP 0-9-1 delivery and by several other features that convert from mc_amqp. The protocol process can terminate before delivering the message. With acknowledgement-required consumers, the entry can be requeued and trigger the same failure after reconnection.

For malformed amqp-sequence and amqp-value classifications, RabbitMQ usually transports the bytes as opaque AMQP-encoded payload instead of decoding them during conversion.

Minimal deterministic proof of concept

After building the core broker from the repository root with make -C deps/rabbit run:

erl -noshell -pa deps/*/ebin -eval ' Payload = << 0, 16#a3, 17, "amqp:data:binary", 16#40, 16#a0, 3, "abc" >>, Fast = catch amqp10_binary_parser:parse_many(Payload, [server_mode]), Full = catch amqp10_framing:decode_bin(Payload), Message = mc:init(mc_amqp, Payload, #{}), Stored = mc:prepare(store, Message), Forwarded = iolist_to_binary(mc:protocol_state(Stored)), RawPreserved = binary:match(Forwarded, Payload) =/= nomatch, Converted = catch mc:convert(mc_amqpl, Stored), io:format("FAST=~0p~nFULL=~0p~nRAW_PRESERVED=~0p~nCONVERTED=~0p~n", [Fast, Full, RawPreserved, Converted]), [{{pos, 0}, {body, 117}}] = Fast, {'EXIT', {unknown, {symbol, <<"amqp:data:binary@">>}}} = Full, true = RawPreserved, {'EXIT', {unknown, {symbol, <<"amqp:data:binary@">>}}} = Converted, halt(). '

Expected output:

FAST=[{{pos,0},{body,117}}] FULL={'EXIT',{unknown,{symbol,<<"amqp:data:binary@">>}}} RAW_PRESERVED=true CONVERTED={'EXIT',{unknown,{symbol,<<"amqp:data:binary@">>}}}

Security impact

Confirmed:

  • RabbitMQ classifies the well-formed unknown descriptor amqp:data:binary@ as a standard data body
  • Classic, quorum, and stream queues preserve the colliding bytes for AMQP 1.0 delivery
  • Raw AMQP 1.0 consumers receive those bytes unchanged
  • Normal RabbitMQ AMQP 1.0 client sessions terminate while decoding the entry
  • AMQP 0-9-1 consumption fails during broker-side conversion on classic and quorum queues
  • Acknowledgement-required consumption can repeatedly redeliver the stored poison entry
  • The RabbitMQ node remains alive after the demonstrated consumer failures

Routing-sensitive metadata is parsed before the body marker. Bytes following the body marker are not used to select the target exchange, routing key, or authorization decision.

Severity

The issue crosses a tenant boundary when an authorized publisher can place a message into a queue consumed by another principal, but the direct impact is availability of consumer sessions or channels rather than compromise of the RabbitMQ node.

The availability effect is not unique to symbolic prefix collisions: server_mode also stops before validating the encoded value of a canonical body descriptor. The prefix-collision defect should therefore be fixed, but the broader body-validation boundary should be considered at the same time.

The immediate six-clause fix prevents symbolic prefix collisions, but it does not remove the stored poison-message primitive. Numeric body-descriptor fast paths also stop before validating the body value. Ingress body validation or controlled conversion errors are required to address that broader availability boundary.

Recommended remediation

For the immediate defect:

  • Require exact symbolic descriptor lengths in all six fast-path clauses
  • Use 16 for data, 23 for sequence, and 17 for value
  • Fall through to normal parsing when the length is not exact
  • Return a controlled AMQP decode error instead of accepting the body marker

For defense in depth:

  • Validate the first body descriptor and encoded body value at ingress
  • Validate legal message section ordering through the end of the payload
  • Catch parser and framing exits at protocol conversion boundaries
  • Reject or dead-letter malformed stored entries without terminating consumer protocol processes

Regression tests

Add coverage for:

  • sym8 lengths 0, expected minus one, expected plus one, and 255
  • sym32 lengths 0, expected minus one, expected plus one, and 16#ffffffff
  • Well-formed unknown descriptors that extend each registered descriptor prefix
  • Structurally inconsistent truncated and unfulfilled overlong symbol encodings
  • Data, sequence, and value symbolic descriptors
  • Classic, quorum, and stream queue persistence
  • AMQP 1.0 normal and raw consumers
  • AMQP 0-9-1 conversion with acknowledgement-required consumption

Пакеты

Наименование

rabbitmq

vmware
Затронутые версииВерсия исправления

>= 4.3.0, < 4.3.4

4.3.4

Наименование

rabbitmq

vmware
Затронутые версииВерсия исправления

>= 4.2.0, < 4.2.10

4.2.10

Наименование

rabbitmq

vmware
Затронутые версииВерсия исправления

>= 4.1.0, < 4.1.15

4.1.15

Наименование

rabbitmq

vmware
Затронутые версииВерсия исправления

>= 4.0.0, < 4.0.24

4.0.24

5.3 Medium

CVSS4

Дефекты

CWE-20
CWE-248
CWE-754

5.3 Medium

CVSS4

Дефекты

CWE-20
CWE-248
CWE-754