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

exploitDog

github логотип

GHSA-5jgm-jxp7-gwjh

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

Описание

MQTT retained message store has no size or count limit and is never reclaimed

Summary

Any authenticated MQTT client with ordinary write permission can retain-publish to unlimited distinct topics. The retained store has no count or size cap, is held in resident memory, and is never reclaimed; it survives restart and cannot be enumerated or bulk-purged. Filling it latches the node's memory alarm permanently, after which no MQTT client can connect at all.

Affected

  • deps/rabbitmq_mqtt/src/rabbit_mqtt_retained_msg_store_{dets,ets}.erl
  • Requires the rabbitmq_mqtt plugin (not enabled by default)
  • Ecosystem: Other: RabbitMQ Package: rabbitmq-server
  • Confirmed on 4.3.4. Code unchanged since 6ac8d4def5 (2015-04-23); wider range inferred, not tested.

Mechanism

insert/3 is an unconditional write: no count check, no size check, and no config setting exists to add one (max_retained and equivalents do not exist anywhere in the plugin or its schema):

insert(Topic, Msg, #store_state{table = T}) -> true = ets:insert(T, #retained_message{topic = Topic, mqtt_msg = Msg}), ok.

The default DETS backend is opened {ram_file, true}, keeping contents resident.

The store exports only start/insert/lookup/delete/expire/terminate. delete/2 needs an exact topic name; there is no enumeration, no bulk purge, and no management API or UI surface. The only expiry is MQTT 5's Message Expiry Interval — client-supplied and optional, so an attacker omits it.

Every comparable store in RabbitMQ has controls this one lacks: queues have max-length, max-length-bytes, policy-applied TTL, overflow behaviour, UI visibility, one-click purge, and drain on consumption. The retained store has none of them.

Reproduction

docker run -d --name rmq --network rmqnet -p 1883:1883 rabbitmq:4.3.4 docker exec rmq rabbitmq-plugins enable rabbitmq_mqtt docker exec rmq rabbitmqctl add_user mqttuser mqttpass docker exec rmq rabbitmqctl set_permissions -p / mqttuser ".*" ".*" ".*" head -c 1048576 /dev/zero | tr '\0' 'A' > /tmp/payload.bin docker run --rm --network rmqnet -v /tmp:/p eclipse-mosquitto sh -c ' for i in $(seq 1 300); do mosquitto_pub -h rmq -p 1883 -u mqttuser -P mqttpass -q 1 -r \ -t "load/topic$i" -f /p/payload.bin done' docker exec rmq rabbitmqctl eval '[{T, dets:info(T,size), dets:info(T,file_size)} || T <- dets:all()].' docker exec rmq rabbitmqctl eval 'erlang:memory(total).'
MeasurementBeforeAfter 300 × 1 MBAfter restart
entries0300300
store bytes5,464618,665,790618,665,790

erlang:memory(total) = 680,066,486, of which the store is 618,665,790 -> 91% of broker memory (idle node: ~100–150 MB). All 300 accepted, no rejection or throttling. ~2x amplification: 300 MB published becomes 618 MB permanently held.

Alarm and denial of service

With the watermark pinned low to shorten the test (set_vm_memory_high_watermark absolute "500MB"), 222 messages latched the alarm at 552 MB:

[{{resource_limit,memory,rabbit@8a4927e6c16d},[]}] [warning] *** Publishers will be blocked until this alarm clears *** [error] closing MQTT connection <<"...:56674 -> ...:1883">> (login timeout) [error] closing MQTT connection <<"...:50776 -> ...:1883">> (login timeout) (repeating every 10s)

Every subsequent connection fails its handshake and is dropped at the login timeout. A client probe returns MOSQ_ERR_CONN_LOST (exit 7). Still latched 4.5 minutes later with no publishing and no recovery.

Impact

While the alarm is latched, new MQTT clients cannot connect; not just publishers, not just the attacker's. The listener is dead to all clients until an operator intervenes.

Unlike queue backlog, this never self-heals: queues drain as consumers catch up and the alarm clears; retained messages never drain. The store is per-vhost, so write access in several vhosts multiplies it.

Limitations

  • DETS files cap near 2 GB, so a single vhost's store is not literally unbounded. At ~2x amplification ~1 GB of publishing fills it; 2 GB unreclaimable resident memory still trips the default watermark on any node under ~3.3 GB, and the per-vhost scoping bypasses the single-table limit. ETS backend untested.
  • Only 4.3.4 tested. Single node; cluster alarm propagation not measured.
  • The alarm test pinned the watermark to 500 MB. This reduces the data volume required, not the mechanism.

Пакеты

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

rabbitmq

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

>= 4.3.0, < 4.3.5

4.3.5

6 Medium

CVSS4

Дефекты

CWE-400
CWE-770

6 Medium

CVSS4

Дефекты

CWE-400
CWE-770
Уязвимость GHSA-5jgm-jxp7-gwjh