Описание
Authenticated RabbitMQ JMS Topic Selector Users Can Consume Broker CPU with an Unbounded LIKE Regular Expression
Advisory Details
Title: Authenticated RabbitMQ JMS Topic Selector Users Can Consume Broker CPU with an Unbounded LIKE Regular Expression
Description:
rabbitmq_jms_topic_exchange accepts a client-provided JMS selector in the rjms_erlang_selector AMQP binding argument. Its LIKE evaluator expands % and _ into PCRE fragments, then executes the generated expression with raw re:run/3 without match or recursion limits. An authenticated AMQP user with normal vhost permissions can bind an x-jms-topic exchange using an ambiguous LIKE pattern and repeatedly publish a matching-shaped header value, consuming broker CPU during message routing.
Summary
This is an authenticated network denial-of-service issue in RabbitMQ Server's optional first-party JMS Topic Exchange plugin. The issue was reproduced end-to-end against RabbitMQ 4.3.1 using only AMQP 0-9-1 operations as a no-tag user. A 601-byte %_-repeated selector and a 1200-byte non-matching message header produced a 0.082410 s median publisher-confirm latency, compared with 0.000525 s for an equal-length non-ambiguous control, a 157.0x slowdown.
The highest released version verified to contain the vulnerable source is RabbitMQ 4.3.2 (v4.3.2, commit a509158b1b1e21c892a7f1dacbe0d158076dc7b8).
Details
The affected component is rabbitmq_jms_topic_exchange, which supplies the x-jms-topic exchange type. A client binds a queue with the rjms_erlang_selector table argument. rabbit_jms_topic_exchange:validate_binding/2 accepts a selector if it parses, and add_binding/3 builds and stores a closure for later routing. When a message is published, route/3 obtains the message headers and invokes that closure.
The vulnerable LIKE path in sjx_evaluator.erl converts % to .* and _ to ., then directly executes the generated pattern:
The call has no {match_limit, ...} or {match_limit_recursion, ...} options. The same release includes rabbit_re:run/3, which applies a 50_000 match and recursion limit, and rabbit_re:compile/1, which enforces a 1024-byte pattern bound. The JMS evaluator bypasses both helpers.
The reproducer uses the valid selector:
%_ becomes .*.. Repeating it creates many overlapping ways to consume the same input. Publishing p = "a" * 1200 ensures that the final literal X cannot match, so the regular-expression engine must explore many failed alternatives before routing can complete. The cost occurs synchronously on the broker's message-routing path and delays publisher confirms.
PoC
Prerequisites
- Docker and Docker Compose
- Python 3.12 or a container capable of installing
pika==1.4.1 - A local port binding for
127.0.0.1:5673and127.0.0.1:15673 - The supplied Compose environment, which runs RabbitMQ 4.3.1 and enables
rabbitmq_jms_topic_exchange
The runtime trigger itself uses only an authenticated AMQP account with ordinary / vhost configure, write, and read permissions. The test user has no RabbitMQ user tags. Administrative setup is only needed to create the isolated test instance and enable the optional plugin.
Reproduction Steps
-
Download the isolated environment files:
-
Download the primary minimal reproducer: manual_minimal_poc.py
-
Make the shell scripts executable, then start the isolated broker:
chmod +x start.sh stop.sh ./start.sh -
Install the AMQP client dependency and run the crafted selector:
pip install pika==1.4.1 SAMPLES=10 python manual_minimal_poc.py candidate -
Run the equal-length control through the same account, connection type, exchange type, header length, and publisher-confirm path:
SAMPLES=10 python manual_minimal_poc.py control -
The candidate should report
result=backtracking-observedwith a materially highermedian_seconds; the control should reportresult=normal-routing -
Stop and remove the isolated environment:
./stop.sh
Supporting scripts uploaded separately as secret Gists:
- amqp_like_timing.py, shared timing harness used by the wrapper tests
- verification_test.py, candidate wrapper for the timing harness
- control-normal-like.py, equal-length control wrapper
- verification_test_Advisory-GHSA-59c5-553c-57m2.py, earlier standalone candidate and baseline harness
Log of Evidence
The fresh end-to-end run used the official RabbitMQ 4.3.1 image pinned by digest, enabled rabbitmq_jms_topic_exchange, and connected through the public AMQP listener at 127.0.0.1:5673.
The candidate was approximately 157.0x slower than the control. A separate six-sample candidate run recorded a 0.080652 s median. Historical 160-sample measurements in the same isolated environment recorded a 0.080756 s candidate median versus 0.000685 s for the equal-length control, and broker CPU increased by 1305 ticks for the candidate versus 20 ticks for the control.
During the run, the management API independently returned the live binding and its full rjms_erlang_selector value. rabbitmqctl list_users showed attacker with [] tags, and the vhost permissions were ordinary .* configure, write, and read permissions.
Impact
An authenticated tenant that is allowed to bind and publish to an x-jms-topic exchange can repeatedly consume RabbitMQ scheduler CPU while messages are routed. This delays publisher confirms and competes with unrelated broker work on the same node. The attacker can amplify the effect by publishing more messages or using multiple bindings, channels, or connections.
The issue does not provide message disclosure, privilege escalation, or code execution. Its demonstrated impact is availability degradation. The reproduction establishes substantial per-message CPU amplification but does not claim that a single test connection alone causes a complete node outage.
Affected products
- Ecosystem: Other
- Package name: RabbitMQ Server
- Affected versions: <= 4.3.2
- Patched versions:
Severity
- Severity: Medium
- Vector string: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H
Weaknesses
- CWE: CWE-1333: Inefficient Regular Expression Complexity
Occurrences
| Permalink | Description |
|---|---|
| https://github.com/rabbitmq/rabbitmq-server/blob/a509158b1b1e21c892a7f1dacbe0d158076dc7b8/deps/rabbitmq_jms_topic_exchange/src/sjx_evaluator.erl#L103-L108 | patt_match/2 invokes raw re:run/3 on the generated pattern and message-header value without match or recursion limits |
| https://github.com/rabbitmq/rabbitmq-server/blob/a509158b1b1e21c892a7f1dacbe0d158076dc7b8/deps/rabbitmq_jms_topic_exchange/src/sjx_evaluator.erl#L133-L143 | pattern_of/2 and convert/3 convert the client-controlled LIKE wildcards into the overlapping .* and . regular-expression fragments |
| https://github.com/rabbitmq/rabbitmq-server/blob/a509158b1b1e21c892a7f1dacbe0d158076dc7b8/deps/rabbitmq_jms_topic_exchange/src/rabbit_jms_topic_exchange.erl#L99-L122 | validate_binding/2 accepts a syntactically valid client selector and add_binding/3 builds and stores its routing closure |
Пакеты
rabbitmq
>= 4.2.0, < 4.2.9
4.2.9
rabbitmq
>= 4.3.0, < 4.3.3
4.3.3
rabbitmq
>= 4.1.0, < 4.1.14
4.1.14
rabbitmq
>= 4.0.0, < 4.0.23
4.0.23