A trailing slash tricks Grafana's bouncer into waving through metric-only tourists
CVE-2025-3454 is an *improper authorization* bug in Grafana's datasource proxy API. Appending an extra / in the URL path defeats the proxy's route-matching allowlist, letting any authenticated Grafana user — even a bare Viewer — issue GET requests against Prometheus and Alertmanager datasources they were never granted. It affects Grafana 8.0 through 11.6.0 (fixed in 10.4.17+security-01, 11.2.8+security-01, 11.3.5+security-01, 11.4.3+security-01, 11.5.3+security-01, and 11.6.0+security-01, released 2 Jun 2025). No write, no code exec, no DoS — just read leakage of metric names, alert rules, and silences that the RBAC layer was supposed to hide.
Vendor MEDIUM (CVSS 5.0, PR:L / C:L / I:N / A:N) is defensible on paper because of the scope change, but in practitioner terms this is a LOW. It requires an authenticated account, is read-only, and the data typically exposed is telemetry that most orgs already treat as internal-general rather than crown-jewel. There is no KEV listing, no public exploit weaponization, and EPSS is essentially floor.
4 steps from start to impact.
Obtain a low-privilege Grafana account
Viewer role is enough. In practice this means a stolen session cookie, phished SSO credential, or a legitimate but over-scoped internal account. Anonymous access must be disabled or the attacker already has an account.- Valid Grafana session
- Network reachability to the Grafana instance
- Grafana is rarely internet-exposed in mature enterprises — usually behind SSO/VPN
- Anonymous auth is off by default in modern deployments
Enumerate datasources visible to the account
GET /api/datasources (or scrapes the UI) to list Prometheus/Alertmanager datasource UIDs. Any datasource the account can *see* — even without proxy permission — is a candidate. Tooling: curl, grafana-api python client, Burp.- Any datasource UID reachable to the account
- RBAC in Grafana Enterprise can hide datasource UIDs from Viewers
/api/datasources/proxy/<uid>/... calls from a single session — easy WAF/access-log signature.Send crafted proxy request with an extra slash
GET /api/datasources/proxy/<uid>//api/v1/query?query=... or //api/v2/alerts. The doubled slash bypasses Grafana's route allowlist match while the upstream Prometheus/Alertmanager still normalizes and serves the request. Weaponization: a 5-line curl loop; no public PoC repo of note as of assessment date.- Vulnerable Grafana version (pre-security-01)
- Datasource UID from step 2
- Prometheus or Alertmanager on the other end of the proxy
- Only Prometheus/Alertmanager proxies are impacted — MSSQL, MySQL, Loki, Tempo proxies are not in the reported blast radius
- GET only — no metric ingestion, silence write, or rule modification
// in the URI — trivially greppable. No native Grafana alert rule ships for this.Exfiltrate metric names, labels, and alert state
/api/v1/label/__name__/values, /api/v1/series, and /api/v2/alerts. This yields the shape of the monitored estate — hostnames, service labels, cloud account IDs, and any firing/silenced alerts. Value depends on how sensitive metric cardinality is in that Prometheus.- Prometheus/Alertmanager returns data on GET
- Impact is proportional to how much sensitive info leaks through label cardinality — often low
- No lateral movement, no privilege escalation, no persistence primitive
label/values and series calls; SIEM correlation on Grafana proxy log + Prom query log is high-signal.The supporting signals.
| CVE | CVE-2025-3454 |
|---|---|
| Vendor severity / score | MEDIUM / CVSS 5.0 (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:N) |
| Tenable VPR | 1.2 (Low) |
| EPSS | ~0.04% (bottom decile) — no observed exploitation |
| CISA KEV | Not listed |
| In-the-wild | No reports of exploitation as of 23 Jul 2026; no active campaigns |
| PoC status | No weaponized public PoC repo. Reproduction is a one-line curl with // in the path — trivial but not packaged |
| Affected versions | Grafana 8.0 through 11.6.0 (all editions: OSS, Enterprise, Cloud) |
| Fixed versions | 10.4.17+security-01, 11.2.8+security-01, 11.3.5+security-01, 11.4.3+security-01, 11.5.3+security-01, 11.6.0+security-01 (2 Jun 2025) |
| Exposure data | Shodan shows ~110k Grafana instances internet-exposed globally; the *authenticated* attack surface is a subset that requires a valid account |
| Reporter | External contributor via pull-request review (credited by Grafana Labs) |
| Disclosed | 2 Jun 2025 alongside CVE-2025-3260 and CVE-2025-2703 |
noisgate verdict.
The single most decisive factor is that this is an authenticated, read-only bypass whose payload is telemetry metadata — not credentials, not code execution, not data-tier records. Blast radius is bounded to whatever Prometheus/Alertmanager exposes over GET, which in the overwhelming majority of deployments is infrastructure metrics rather than regulated data.
Why this verdict
- Authentication required (PR:L): every step in the chain assumes the attacker already holds a Grafana session. That collapses the addressable population from 'internet-random' to 'insider or credential-thief already past IdP/MFA'.
- Read-only, GET-only: no write to silences, no rule mutation, no metric ingestion, no RCE, no DoS. Integrity and availability sub-scores are zero for a reason.
- Narrow datasource scope: only Prometheus and Alertmanager proxies are affected. SQL, Loki, Tempo, InfluxDB, CloudWatch, and other proxy targets are out of scope.
- Role multiplier — typical Grafana role (LOB monitoring dashboard): chain succeeds; blast radius = leak of metric names/labels/alert state. Impact is *reconnaissance-grade*, not compromise-grade.
- Role multiplier — high-value Grafana role (SRE control plane exposing Prometheus with sensitive labels, e.g. tenant IDs, customer names, PII in labels): chain succeeds; blast radius = intelligence leakage that could aid a follow-on targeted attack. Still not fleet-scale, not domain takeover, not supply-chain — floor stays at LOW/MEDIUM, not HIGH. Grafana is *not* a canonical high-value-role component (it's not an IdP, hypervisor, PAM, backup, or kernel-mode agent), so the CRITICAL floor does not apply.
- No KEV, no active exploitation, EPSS near floor: none of the amplifiers that would override the friction-driven downgrade are present.
Why not higher?
MEDIUM would require either a wider datasource scope (write, or non-Prom datasources), or an unauthenticated variant. Neither exists. HIGH would require impact on integrity/availability or role-multiplier evidence that Grafana routinely sits in a domain-takeover-adjacent position — it does not.
Why not lower?
IGNORE is inappropriate because there *is* real information disclosure — metric labels frequently encode tenant identifiers, hostnames, and cloud account IDs that are useful to an attacker doing target selection. It belongs in the backlog, not the trash.
What to do — in priority order.
- Enforce SSO + MFA on all Grafana logins and disable anonymous access — Removes the *bring-your-own-account* variant. Verify
[auth.anonymous] enabled = falseand that[auth.basic]is off in favor of your IdP. As a LOW verdict there is no noisgate mitigation SLA — bundle this into your normal identity hygiene cadence rather than treating it as an emergency. - Add a WAF / reverse-proxy rule normalizing or rejecting
//in/api/datasources/proxy/*paths — A single nginxmerge_slashes on;or an Envoynormalize_pathdirective collapses the double slash before Grafana sees it. Deploy alongside your next regular WAF ruleset push — no mitigation SLA applies at LOW. - Audit Prometheus label cardinality for sensitive fields — If your Prometheus labels contain tenant IDs, customer names, or PII, the impact of this bug (and many future ones) is materially higher. Add this to Q3 backlog and treat as ongoing hygiene.
- Schedule the security-01 patch train in the next regular Grafana maintenance window — Ride the noisgate remediation SLA of ≤ 365 days. The upgrade to
10.4.17+security-01/11.x.y+security-01is a routine minor bump with no schema or plugin-API breaking changes.
- Network-level blocking of Grafana — the bug is triggered by an authenticated user, so a public/private split doesn't reduce the internal-attacker case.
- Grafana RBAC datasource permissions alone — the whole point of the CVE is that the proxy layer bypasses RBAC when the URL has a stray slash.
- Turning off Alertmanager UI — the bypass targets the *proxy path*, not the UI; the Alertmanager datasource itself must be removed or the version patched.
- CSP / browser-side mitigations — this is a server-side auth check bug; browser policy is irrelevant.
Crowdsourced verification payload.
Run on any host with network access to the Grafana instance (auditor workstation is fine). No credentials required — this checks the advertised build version via the public /api/health endpoint. Invoke: ./check_grafana_3454.sh https://grafana.corp.example.com. Exit 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN.
#!/usr/bin/env bash
# noisgate verification for CVE-2025-3454 (Grafana datasource proxy auth bypass)
# Usage: ./check_grafana_3454.sh <grafana_base_url>
set -u
URL="${1:-}"
if [[ -z "$URL" ]]; then
echo "Usage: $0 <grafana_base_url>" >&2
exit 2
fi
JSON=$(curl -sk --max-time 10 "${URL%/}/api/health") || {
echo "UNKNOWN: could not reach $URL/api/health"; exit 2; }
VER=$(echo "$JSON" | grep -oE '"version"[[:space:]]*:[[:space:]]*"[^"]+"' | sed -E 's/.*"([^"]+)"$/\1/')
if [[ -z "$VER" ]]; then echo "UNKNOWN: no version in /api/health response"; exit 2; fi
echo "Detected Grafana version: $VER"
# Strip metadata; keep base semver and security tag if present
BASE=$(echo "$VER" | awk -F'[+ -]' '{print $1}')
SEC_TAG=$(echo "$VER" | grep -oE 'security-[0-9]+' | head -1)
IFS='.' read -r MAJ MIN PAT <<<"$BASE"
fixed() { echo "PATCHED: $VER contains security fix for CVE-2025-3454"; exit 0; }
vuln() { echo "VULNERABLE: $VER is below the +security-01 fix train for CVE-2025-3454"; exit 1; }
# Any 12.x is post-fix
if (( MAJ >= 12 )); then fixed; fi
# Require security-01 tag on the affected minor lines
if (( MAJ == 11 )); then
case "$MIN" in
2) [[ -n "$SEC_TAG" && "$PAT" -ge 8 ]] && fixed || vuln ;;
3) [[ -n "$SEC_TAG" && "$PAT" -ge 5 ]] && fixed || vuln ;;
4) [[ -n "$SEC_TAG" && "$PAT" -ge 3 ]] && fixed || vuln ;;
5) [[ -n "$SEC_TAG" && "$PAT" -ge 3 ]] && fixed || vuln ;;
6) [[ -n "$SEC_TAG" ]] && fixed || vuln ;;
7|8|9|10|11|12) fixed ;; # 11.7+ ships fix inline
*) vuln ;;
esac
fi
if (( MAJ == 10 )); then
if (( MIN == 4 )) && [[ -n "$SEC_TAG" && "$PAT" -ge 17 ]]; then fixed; else vuln; fi
fi
if (( MAJ < 10 )); then vuln; fi
echo "UNKNOWN: version $VER did not match any known branch"; exit 2
If you remember one thing.
merge_slashes on; (or equivalent) at your reverse proxy to collapse // before Grafana sees it, and add the +security-01 bump to the next scheduled Grafana maintenance window. Per the noisgate mitigation SLA, LOW carries no mitigation deadline — skip straight to the noisgate remediation SLA of ≤ 365 days for the actual upgrade. Escalate only if your Prometheus labels contain regulated data (tenant IDs, PII, customer identifiers), in which case bump the compensating-control work to the front of the next sprint.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.