<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="https://belz.news/feed_style.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <tabi:metadata xmlns:tabi="https://github.com/welpo/tabi">
        <tabi:base_url>https://belz.news</tabi:base_url>
        <tabi:separator>
            •
        </tabi:separator>
        <tabi:about_feeds>
            This is a web feed, also known as an Atom feed. Subscribe by copying the URL from the address bar into your newsreader. Visit About Feeds to learn more and get started. It's free.
        </tabi:about_feeds>
        <tabi:visit_the_site>
            Visit website
        </tabi:visit_the_site>
        <tabi:recent_posts>
            Recent posts
        </tabi:recent_posts>
        <tabi:last_updated_on>
            Updated on $DATE
        </tabi:last_updated_on>
        <tabi:default_theme></tabi:default_theme>
        <tabi:post_listing_date>date</tabi:post_listing_date>
        <tabi:current_section>cybersecurity</tabi:current_section>
    </tabi:metadata><title>panic!(&quot;ADGTH&quot;) - cybersecurity</title>
        <subtitle>All Dogs Go to Heaven</subtitle>
    <link href="https://belz.news/tags/cybersecurity/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="https://belz.news/tags/cybersecurity/" rel="alternate" type="text/html"/>
    <generator uri="https://www.getzola.org/">Zola</generator><updated>2026-03-13T00:00:00+00:00</updated><id>https://belz.news/tags/cybersecurity/atom.xml</id><entry xml:lang="en">
        <title>RabbitMQ: how messages can leak without a service outage</title>
        <published>2026-03-13T00:00:00+00:00</published>
        <updated>2026-03-13T00:00:00+00:00</updated>
        <author>
            <name>Belz</name>
        </author>
        <link rel="alternate" href="https://belz.news/blog/rabbitmq-mitm/" type="text/html"/>
        <id>https://belz.news/blog/rabbitmq-mitm/</id>
        
            <content type="html">&lt;h2 id=&quot;the-service-works-someone-else-has-read-the-data&quot;&gt;The service works. Someone else has read the data&lt;/h2&gt;
&lt;p&gt;A RabbitMQ data leak does not necessarily look like an outage. The application processes jobs, the queue drains, and users see no failure. Yet some messages may have passed through an unauthorized consumer before reaching the application. A consumer is a client that receives messages from a queue.&lt;/p&gt;
&lt;p&gt;The mechanism is &lt;strong&gt;receive a message → read its contents → return it to the queue with &lt;code&gt;NACK(requeue=true)&lt;/code&gt;&lt;/strong&gt;. Returning it preserves the possibility of subsequent processing, but does not undo the read.&lt;/p&gt;
&lt;p&gt;That is the security issue: &lt;strong&gt;service availability and message confidentiality are different properties&lt;/strong&gt;. A successfully processed job does not prove that only the intended service saw its contents.&lt;/p&gt;
&lt;h2 id=&quot;what-access-is-required&quot;&gt;What access is required&lt;/h2&gt;
&lt;p&gt;This is not an authentication bypass or a network man-in-the-middle (MITM) attack. The scenario assumes an attacker can already connect to the broker and has permission to read the target queue, perhaps through a compromised service account or overly broad access control lists (ACLs). The configuration must also allow another active consumer. [1][3]&lt;/p&gt;
&lt;p&gt;&lt;code&gt;read&lt;/code&gt; permission does not mean passive viewing. A consumer participates in delivery. TLS protects the connection, not the contents from a client the broker permits to receive them.&lt;/p&gt;
&lt;h2 id=&quot;receive-read-return&quot;&gt;Receive, read, return&lt;/h2&gt;
&lt;p&gt;Several active consumers on an ordinary queue share deliveries rather than each receiving a copy of every message. Some messages go to the application; others may go to the unauthorized consumer. Distribution depends on the prefetch limit (the number of unacknowledged deliveries allowed), consumer availability, and queue configuration. An exclusive consumer or Single Active Consumer mode can prevent another consumer from receiving messages alongside the application. [1]&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;publisher → queue → additional consumer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                         │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                         ├─ reads the contents&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                         └─ NACK(requeue=true) → queue → next delivery&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With manual acknowledgements, a delivered message remains unacknowledged until the consumer responds. &lt;code&gt;ACK&lt;/code&gt; confirms receipt and allows the broker to remove the message from the queue. &lt;code&gt;NACK&lt;/code&gt; rejects the delivery; with &lt;code&gt;requeue=true&lt;/code&gt;, it makes the message available for redelivery. This does not create a copy or instruct the broker to deliver specifically to the application. The next recipient may be the application—or the same consumer again. [2]&lt;/p&gt;
&lt;p&gt;If the application subsequently receives and successfully processes the message, the business operation may complete without an apparent failure. Confidentiality has already been lost.&lt;/p&gt;
&lt;h2 id=&quot;why-it-might-go-unnoticed&quot;&gt;Why it might go unnoticed&lt;/h2&gt;
&lt;p&gt;Monitoring that checks only application availability and job completion may produce no obvious alert about the extra reader. The mechanism does not require changing application code or deliberately stopping the service.&lt;/p&gt;
&lt;p&gt;But &lt;strong&gt;unnoticed does not mean invisible&lt;/strong&gt;. Additional consumers and connections appear at the broker, and redeliveries occur. These are observable changes. An absence of user complaints is no substitute for monitoring them.&lt;/p&gt;
&lt;p&gt;There is no guarantee that the service will remain unaffected: delays, changes in delivery order, additional load, and redelivery loops are possible. Queue policies, queue type, and RabbitMQ version also affect the outcome. [2]&lt;/p&gt;
&lt;h2 id=&quot;code-example-returning-does-not-undo-reading&quot;&gt;Code example: returning does not undo reading&lt;/h2&gt;
&lt;p&gt;This is a &lt;strong&gt;local model of one possible sequence&lt;/strong&gt;, not a RabbitMQ client. It uses a synthetic message in memory, makes no connections, and demonstrates the key point: successful processing can follow disclosure to another participant.&lt;/p&gt;
&lt;p&gt;Save it as &lt;code&gt;delivery_model.py&lt;/code&gt; and run &lt;code&gt;python delivery_model.py&lt;/code&gt;. No external packages are required.&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;from&lt;/span&gt;&lt;span&gt; collections&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; import&lt;/span&gt;&lt;span&gt; deque&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Synthetic data only: no network connection or external credentials.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;queue&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt; deque&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;([{&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;demo-1&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;body&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt; &amp;quot;synthetic payload&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;}])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;observed&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;processed&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# Model one possible delivery to an additional consumer.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;message&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; queue&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;popleft&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;observed&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;copy&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;queue&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;appendleft&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;  # Model NACK(requeue=True), not a broker call.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# For this trace, explicitly choose the application as the next recipient.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;# A real broker does not guarantee this recipient after requeue.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;message&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; =&lt;/span&gt;&lt;span&gt; queue&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;popleft&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;processed&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-3&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-7 z-i&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;z-4 z-i&quot;&gt;  # Model successful processing and ACK.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; observed&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;z-1&quot;&gt; ==&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; processed&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-9&quot;&gt;assert not&lt;/span&gt;&lt;span&gt; queue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;Observed:&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; observed&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;Processed:&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-12 z-i&quot;&gt; processed&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-14 z-i&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-7&quot;&gt;&amp;quot;Queue empty:&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-9&quot;&gt; not&lt;/span&gt;&lt;span&gt; queue&lt;/span&gt;&lt;span class=&quot;z-4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The example deliberately chooses the application as the next recipient. Real RabbitMQ requeueing makes no such guarantee. This model does not measure delivery distribution, processing speed, or how noticeable a connection is.&lt;/p&gt;
&lt;h2 id=&quot;what-if-there-are-more-consumers&quot;&gt;What if there are more consumers?&lt;/h2&gt;
&lt;p&gt;Consumer count can affect delivery distribution, but there is no universal formula for the share of messages an unauthorized consumer can read. The proportion of unauthorized consumers does not equal the proportion of unique messages they observe: receiving the same message again does not increase that share, and a message already acknowledged by the application is no longer available from the queue.&lt;/p&gt;
&lt;p&gt;More connections also mean more observable participants and potentially more load. This neither guarantees complete interception nor makes the activity invisible.&lt;/p&gt;
&lt;h2 id=&quot;what-broker-owners-should-check&quot;&gt;What broker owners should check&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Accounts and ACLs.&lt;/strong&gt; Use separate service accounts, restrict read access to required queues, and isolate services in separate virtual hosts where appropriate. [3]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consumers and connections.&lt;/strong&gt; Compare them against the expected topology rather than just checking whether the queue is draining.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redeliveries and latency.&lt;/strong&gt; Increases can have ordinary causes, such as application failures, but need an explanation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network access.&lt;/strong&gt; Expose AMQP and the Management API only to the segments and services that need them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compromise response.&lt;/strong&gt; Revoke access and terminate unwanted connections. Successful message processing does not rule out disclosure.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The danger of “read and return” is not guaranteed invisibility. It is that &lt;strong&gt;disclosure may happen without an obvious service failure&lt;/strong&gt;. A message can return to the queue and be processed, but the data already read cannot be taken back.&lt;/p&gt;
&lt;h2 id=&quot;sources&quot;&gt;Sources&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https://www.rabbitmq.com/docs/consumers&quot;&gt;RabbitMQ: Consumers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https://www.rabbitmq.com/docs/confirms&quot;&gt;RabbitMQ: Consumer Acknowledgements and Publisher Confirms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https://www.rabbitmq.com/docs/access-control&quot;&gt;RabbitMQ: Access Control&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content>
        <summary type="html">An unauthorized consumer can read a message and requeue it with NACK. Why a working service does not guarantee message confidentiality.</summary>
        </entry>
</feed>
