ACT TONIGHT

Grafana and Prometheus: admin/admin, anonymous access, and unauthenticated metrics/pprof endpoints

Risk / Filed 28 Sep 2026 / CVE-2021-43798, CVE-2024-9264, CVE-2025-4123, CVE-2026-27876, CVE-2026-27880

grafanaprometheusnode-exporterdockerdefault-credsexposed-api

What: Out of the box, Grafana listens on all interfaces with admin/admin. Prometheus (:9090) and node_exporter (:9100) have no auth at all, and both serve /debug/pprof. Aqua Nautilus found about 40,000 Prometheus servers and 296,000 exporters open to the internet in Dec 2024. Their metrics and labels were leaking credentials, tokens, API keys and internal hostnames. Anyone can hit pprof to pull out runtime details or tie up the host's resources. On top of the bad defaults, Grafana keeps shipping CVEs:

CVE What Needs Fixed in
CVE-2021-43798 Path traversal, reads files off the host Nothing (unauth) 8.3.1 / 8.2.7 / 8.1.8 / 8.0.7. In CISA KEV since 2025-10-09. GreyNoise logged 110 IPs trying it on 28 Sep 2025
CVE-2025-4123 "Grafana Ghost" Open redirect + path traversal leading to XSS/account takeover. Full-read SSRF if Image Renderer is installed Victim clicks a link. Works with anonymous access on 10.4.18, 11.2.9, 11.3.6, 11.4.4, 11.5.4, 11.6.1 (all +security-01), 12.0.0+security-01
CVE-2024-9264 SQL Expressions command injection/LFI (CVSS 9.9) Viewer account, plus duckdb binary in Grafana's PATH 11.0.5/11.1.6/11.2.1 +security-01 (and later)
CVE-2026-27876 sqlExpressions file write leading to RCE/SSH on the host (CVSS 9.1) Viewer account, plus the sqlExpressions feature toggle 12.4.2, 12.3.6, 12.2.8, 12.1.10, 11.6.14
CVE-2026-27880 Crashes Grafana by exhausting memory Nothing (unauth) Same as above

The Viewer-level bugs are why anonymous access matters. With anonymous on, every visitor gets Viewer by default. Grafana published more fixes in Aug and Sep 2026, so check the advisories page for your version.

Who it hits:

  • Grafana on :3000 port-forwarded, or put on the internet through a Cloudflare Tunnel or reverse proxy, that is still on admin/admin, has [auth.anonymous] enabled = true, or runs an unpatched version.

  • Prometheus :9090 or any exporter (:9100, cAdvisor, etc.) reachable from outside your LAN. Docker's -p 9090:9090 publishes on every interface and skips ufw, so a host firewall doesn't save you.

Check if you're affected:

# What is listening, and on which address (0.0.0.0 / [::] = every interface)
ss -ltnp | grep -E ':(3000|9090|9093|9100)\b'

# Grafana version (compare against the table / advisories page)
curl -s http://HOST:3000/api/health

# Default creds still work? 200 + JSON = yes, 401 = no
curl -s -o /dev/null -w '%{http_code}\n' -u admin:admin http://HOST:3000/api/user

# Anonymous access on? 200 with a list = yes, 401 = no
curl -s -o /dev/null -w '%{http_code}\n' http://HOST:3000/api/search

# Run these from OUTSIDE (phone hotspot / a VPS) against your public IP or hostname.
# Any 200 means strangers see it too.
curl -s -o /dev/null -w '%{http_code}\n' http://PUBLIC:9090/api/v1/targets
curl -s -o /dev/null -w '%{http_code}\n' http://PUBLIC:9090/debug/pprof/
curl -s -o /dev/null -w '%{http_code}\n' http://PUBLIC:9100/metrics
curl -s -o /dev/null -w '%{http_code}\n' http://PUBLIC:9100/debug/pprof/

Do this:

  1. Tonight: delete any port-forward for 3000, 9090, 9093 or 9100 on the router. Never forward Prometheus or exporter ports. If you need to reach them remotely, use a VPN (Tailscale/WireGuard).

  2. Change the Grafana admin password: docker exec -it grafana grafana cli admin reset-admin-password 'LONG-RANDOM' (or change it in the UI under Profile, then Change password). GF_SECURITY_ADMIN_PASSWORD only takes effect on first start and does not change an existing database.

  3. Lock down grafana.ini (or the matching GF_* env vars) and restart: ini [auth.anonymous] enabled = false [users] allow_sign_up = false [server] http_addr = 127.0.0.1 ; if only a local reverse proxy talks to it Use Grafana's public dashboards feature to share a single dashboard, not anonymous access.

  4. Upgrade Grafana to at least the fixed version for your branch in the table, and preferably the newest patch release listed on the advisories page. If you can't upgrade yet: turn off the sqlExpressions feature toggle, make sure duckdb is not in Grafana's PATH, and remove Image Renderer unless you use it.

  5. Keep Prometheus and exporters on localhost or the LAN. Use --web.listen-address=127.0.0.1:9090 (or your LAN IP). In compose, use "127.0.0.1:9090:9090", or leave out ports: and let Prometheus scrape over the Docker network.

  6. Add basic auth on Prometheus and node_exporter with --web.config.file=web.yml: yaml basic_auth_users: prom: $2y$10$... # bcrypt hash, e.g. htpasswd -nBC 10 "" | tr -d ':\n' node_exporter has no flag to turn off /debug/pprof (upstream closed that request as not planned). Auth or network restriction is the only fix.

  7. Verify: rerun the outside curls. Every one should time out or return 401.

If you were already hit: Treat every data source credential and token stored in Grafana as leaked, along with any secrets that showed up in Prometheus labels. Rotate them, check the Grafana users and API/service-account tokens for ones you didn't create, and rebuild the host if you were on a version vulnerable to the RCE bugs.

Why this level: It hits all five: the ports are commonly forwarded, Grafana is actively scanned (GreyNoise, CISA KEV), it's core lab software, it leaks secrets or gives RCE, and the defaults need no credentials. If nothing answers from outside, treat it as this-week.

Sources

How severity is decided. Source file: risks/2026-09-28-grafana-prometheus-default-exposure.md.