Like leaving a master key list taped to a window nobody opens, in a building wing that's been condemned
CVE-2026-27877 is an information disclosure flaw in Grafana's public dashboards feature. When a Grafana instance has public dashboards enabled *and* uses direct (browser) access mode data sources, all direct-mode data-source passwords are exposed to anyone who can reach the public dashboard URL — even if those data sources aren't used by the dashboard itself. Proxied (server-mode) data sources are not affected. The bug spans Grafana 9.3.0 through 11.6.13, 12.0.0 through 12.1.9, 12.2.0 through 12.2.7, 12.3.0 through 12.3.5, and 12.4.0 through 12.4.1. Fixed in 11.6.14, 12.1.10, 12.2.8, 12.3.6, and 12.4.2.
Tenable rates this HIGH at CVSS 7.5, treating it as unauthenticated (PR:N) since public dashboards require no login. Grafana's own advisory rates it MEDIUM at CVSS 6.5 (PR:L). In practice, Tenable's framing is closer to correct on the auth question — public means public — but the severity is inflated because the *direct access mode* prerequisite is a dead feature. Direct/browser mode was deprecated in Grafana 7.4.0 (2021) and removed entirely for Elasticsearch in 9.0 and Prometheus in 9.2. Any Grafana instance in the affected range (≥9.3.0) running these core data sources physically cannot have direct mode active. Only third-party or community plugins with custom direct-mode support remain in scope, which is a vanishingly small population. Tenable's own VPR score of 3.0 (Low) tacitly agrees — the real-world risk doesn't match the CVSS label.
4 steps from start to impact.
Discover a Grafana instance with public dashboards
/public-dashboards/<accessToken>). Enumeration is trivial if the instance is internet-facing.- Grafana instance is network-reachable (internet-facing or internal)
- At least one public dashboard has been created and shared
- Many enterprise Grafana deployments are internal-only behind VPN/ZTNA
- Public dashboards must be explicitly created by a dashboard owner — they are not on by default for any dashboard
http.title:Grafana on port 3000. WAF/reverse-proxy logs will show requests to /public-dashboards/*.Access the public dashboard endpoint
accessToken in the URL is the only gate. The response includes dashboard JSON and associated data-source metadata. If direct-mode data sources exist, their connection strings and cleartext passwords are embedded in the response payload.- The public dashboard access token is known or guessable
- Direct-mode data sources are configured on the Grafana instance
- Direct/browser access mode was deprecated in Grafana 7.4 and removed for Elasticsearch (9.0) and Prometheus (9.2). The affected version range starts at 9.3.0, meaning core data sources already lack direct mode.
- Only third-party plugins that independently implement direct mode remain vulnerable — a niche population
- Access tokens are UUIDs, not enumerable without prior knowledge or a directory listing bug
/public-dashboards/<token>.Extract data-source credentials from the response
- Direct-mode data sources exist with stored passwords
- Modern Grafana best practice and provisioning defaults use proxy/server mode, where credentials never leave the backend
- Many deployments use service accounts, API keys, or IAM roles rather than password-based authentication for data sources
Pivot to backend data sources using leaked credentials
- Network path from attacker to the backend data source
- Leaked credentials are still valid and not rotated
- Backend data source accepts connections from non-Grafana IPs
- Backend databases are almost never internet-facing — firewall rules typically restrict source IPs to the Grafana server
- Credential rotation, IP allowlisting, and mutual TLS on database connections break this step
- The attacker gains read access to monitoring data, not necessarily production application data
The supporting signals.
| In-the-Wild Exploitation | No evidence. Not listed in CISA KEV. No campaigns, threat reports, or honeypot hits documented as of 2026-09-21. |
|---|---|
| Proof-of-Concept | None publicly available. No PoC repos on GitHub, no researcher write-ups demonstrating the credential extraction. The attack is conceptually simple (hit a public dashboard URL, read JSON) but the preconditions limit practical reproduction. |
| EPSS Score | < 1% — bottom tier. Consistent with no weaponization activity. |
| KEV Status | Not listed in CISA Known Exploited Vulnerabilities catalog. |
| CVSS Vectors | Grafana: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N (6.5 MEDIUM). Tenable: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N (7.5 HIGH). Delta is PR:L vs PR:N — Tenable correctly notes public dashboards need no auth. VPR: 3.0 (Low). |
| Affected Versions | Grafana 9.3.0 – 11.6.13, 12.0.0 – 12.1.9, 12.2.0 – 12.2.7, 12.3.0 – 12.3.5, 12.4.0 – 12.4.1 |
| Fixed Versions | 11.6.14, 12.1.10, 12.2.8, 12.3.6, 12.4.2. RHEL backports: RHSA-2026:10223, RHSA-2026:10226, RHSA-2026:11416, RHSA-2026:11417, RHSA-2026:19134, RHSA-2026:19352 (RHEL 9/10). |
| Exposure Data | Shodan indexes ~128,000 Grafana instances globally. However, the subset using both public dashboards AND deprecated direct-mode data sources is estimated to be extremely small — direct mode was removed from core data sources in Grafana 9.0–9.2. |
| Disclosure Date | 2026-03-27 (Grafana advisory). Tenable plugin published 2026-04-02. |
| Credit | Not publicly attributed in the Grafana advisory. |
Why this verdict
- Deprecated prerequisite eliminates most of the attack surface. Direct/browser access mode was deprecated in Grafana 7.4 (2021) and *removed* for Elasticsearch in 9.0 and Prometheus in 9.2. The affected version range begins at 9.3.0 — meaning core data sources in affected versions cannot use direct mode. Only third-party plugins with independent direct-mode implementations remain exploitable. This shrinks the reachable population to well under 1% of Grafana deployments.
- Public dashboards must be explicitly created. The feature toggle enables the *capability*, but each dashboard must be individually published by an editor/admin. Organizations running Grafana for internal monitoring rarely create public dashboards. The overlap of 'public dashboard exists' AND 'direct-mode data source configured' is vanishingly narrow.
- Credential leak requires a second hop that rarely succeeds. Even when credentials are extracted, the attacker must reach the backend data source over the network. Backend databases are almost universally firewalled to accept connections only from application/Grafana server IPs. The credential alone is insufficient without network access.
- Role multiplier: Grafana as observability/SIEM-adjacent tier. Grafana occupies the monitoring/detection plane. If this chain succeeded, leaked credentials would typically grant read access to metrics stores (Prometheus, InfluxDB) or log aggregators (Elasticsearch) — not identity stores, domain controllers, or production transactional databases. The blast radius is host-to-tenant scope at most, not domain/fleet/supply-chain. Because the deprecated-feature prerequisite means <1% of Grafana installs can be hit, the SIEM/detection-plane floor (HIGH) is not triggered.
- Tenable's own VPR of 3.0 (Low) agrees. The Vulnerability Priority Rating, which factors in threat intelligence, exploit maturity, and real-world conditions, scores this at the bottom of its scale — contradicting the CVSS-derived HIGH label on the same plugin.
Why not higher?
The CVSS 7.5 HIGH score from Tenable correctly identifies that no authentication is needed (public dashboard = PR:N) and the confidentiality impact is high (cleartext passwords). However, the score ignores that the vulnerable configuration — direct-mode data sources — is a deprecated and largely removed feature in the affected version range. Without adjusting for this real-world precondition, the CVSS score overstates the reachable attack surface by orders of magnitude.
Why not lower?
Despite the narrow preconditions, the vulnerability is unauthenticated, requires zero user interaction, and exposes cleartext database passwords — credentials that could unlock lateral movement if network conditions permit. A small number of organizations may still use third-party plugins with direct-mode support behind public dashboards, and for those outliers the impact is real. Additionally, ~128K Grafana instances are internet-facing, so the base exposure surface is non-trivial even if the vulnerable subset is tiny. LOW would understate the potential impact for the small population that is genuinely affected.
What to do — in priority order.
- Convert all direct-mode data sources to proxy/server mode — This is the most effective mitigation and eliminates the vulnerability entirely. In proxy mode, credentials never leave the Grafana backend and are not included in dashboard API responses. Grafana's provisioning API or UI (
Data Sources > Settings > Access: Server) can be used for this change. As a MEDIUM-severity finding, no mitigation SLA applies — go straight to the 365-day remediation window, but this config change is low-effort and can be done immediately. - Audit and disable unnecessary public dashboards — Run
curl -s -H 'Authorization: Bearer <admin-token>' https://<grafana>/api/dashboards/public-dashboardsto list all public dashboards. Disable any that are not actively required. Each disabled public dashboard removes an exposure point for this CVE. - Rotate all data-source credentials immediately if you had public dashboards + direct mode — If your instance had both conditions active, treat all direct-mode data-source passwords as compromised. Rotate credentials in the backend data sources and update Grafana's stored credentials. This is a one-time remediation task.
- Place Grafana behind a reverse proxy with authentication — Even for public dashboards, a reverse proxy (nginx, Cloudflare Access, Pomerium) can add rate limiting, IP allowlisting, and an authentication layer. This prevents casual internet enumeration and limits exposure.
- Upgrade to a fixed Grafana version within the 365-day noisgate remediation SLA — Apply the vendor patch: 11.6.14, 12.1.10, 12.2.8, 12.3.6, or 12.4.2. RHEL users can apply RHSA-2026:19352 or equivalent. Since this is MEDIUM with no active exploitation, the noisgate remediation SLA gives you up to 365 days, but the fix is a straightforward version bump.
- Disabling the public dashboards feature toggle alone does not retroactively remove already-published public dashboards in all versions. You must individually unpublish each dashboard or upgrade to a fixed version.
- Network segmentation of Grafana reduces the initial access risk but does not fix the vulnerability — internal attackers or compromised internal hosts can still reach public dashboard URLs.
- **WAF rules blocking
/public-dashboards/*** will break legitimate public dashboard functionality. This is a sledgehammer approach that should only be used if you intend to disable public dashboards entirely.
Crowdsourced verification payload.
Run this script from any host that can reach the Grafana instance's HTTP API. Usage: bash check_cve_2026_27877.sh https://grafana.example.com. No authentication is required for the version check; admin API token is optional but recommended for the direct-mode data-source audit. The script checks version and optionally inspects data-source access modes.
#!/usr/bin/env bash
# check_cve_2026_27877.sh — CVE-2026-27877 Grafana public dashboard credential leak
# Usage: bash check_cve_2026_27877.sh <GRAFANA_URL> [ADMIN_API_TOKEN]
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN
set -euo pipefail
GRAFANA_URL="${1:?Usage: $0 <GRAFANA_URL> [ADMIN_API_TOKEN]}"
GRAFANA_URL="${GRAFANA_URL%/}"
TOKEN="${2:-}"
# Fetch version from /api/health
HEALTH=$(curl -sf --max-time 10 "${GRAFANA_URL}/api/health" 2>/dev/null) || {
echo "UNKNOWN — cannot reach ${GRAFANA_URL}/api/health"
exit 2
}
VERSION=$(echo "$HEALTH" | grep -oP '"version"\s*:\s*"\K[0-9]+\.[0-9]+\.[0-9]+' || true)
if [[ -z "$VERSION" ]]; then
echo "UNKNOWN — could not parse Grafana version from health endpoint"
exit 2
fi
echo "Detected Grafana version: $VERSION"
# Version comparison helper
ver_lt() {
[ "$(printf '%s\n' "$1" "$2" | sort -V | head -n1)" = "$1" ] && [ "$1" != "$2" ]
}
# Check affected ranges
VULN=false
if ver_lt "$VERSION" "11.6.14" && ! ver_lt "$VERSION" "9.3.0"; then
VULN=true
FIX="11.6.14"
elif ver_lt "$VERSION" "12.1.10" && ! ver_lt "$VERSION" "12.0.0"; then
VULN=true
FIX="12.1.10"
elif ver_lt "$VERSION" "12.2.8" && ! ver_lt "$VERSION" "12.2.0"; then
VULN=true
FIX="12.2.8"
elif ver_lt "$VERSION" "12.3.6" && ! ver_lt "$VERSION" "12.3.0"; then
VULN=true
FIX="12.3.6"
elif ver_lt "$VERSION" "12.4.2" && ! ver_lt "$VERSION" "12.4.0"; then
VULN=true
FIX="12.4.2"
fi
if [[ "$VULN" == "false" ]]; then
echo "PATCHED — Grafana $VERSION is not in any affected range."
exit 0
fi
echo "VERSION AFFECTED — $VERSION is vulnerable (fix: >= $FIX)"
# Optional: check for direct-mode datasources (requires admin token)
if [[ -n "$TOKEN" ]]; then
echo ""
echo "Checking data-source access modes (requires admin privileges)..."
DS_JSON=$(curl -sf --max-time 10 -H "Authorization: Bearer ${TOKEN}" "${GRAFANA_URL}/api/datasources" 2>/dev/null) || {
echo "WARNING — could not query /api/datasources (check token permissions)"
}
if [[ -n "${DS_JSON:-}" ]]; then
DIRECT_COUNT=$(echo "$DS_JSON" | grep -co '"access":"direct"' || echo 0)
TOTAL_COUNT=$(echo "$DS_JSON" | grep -co '"access":' || echo 0)
echo "Data sources: $TOTAL_COUNT total, $DIRECT_COUNT using direct/browser mode"
if [[ "$DIRECT_COUNT" -gt 0 ]]; then
echo "WARNING — direct-mode data sources found. These are exposed via public dashboards."
else
echo "NOTE — no direct-mode data sources found. Exploitability is minimal even without patching."
fi
fi
# Check for public dashboards
PD_JSON=$(curl -sf --max-time 10 -H "Authorization: Bearer ${TOKEN}" "${GRAFANA_URL}/api/dashboards/public-dashboards" 2>/dev/null) || true
if [[ -n "${PD_JSON:-}" ]]; then
PD_COUNT=$(echo "$PD_JSON" | grep -co '"uid":' || echo 0)
echo "Public dashboards found: $PD_COUNT"
if [[ "$PD_COUNT" -eq 0 ]]; then
echo "NOTE — no public dashboards active. Vulnerability is not reachable."
fi
fi
else
echo ""
echo "TIP: Pass an admin API token as the second argument to check for direct-mode data sources and public dashboards."
fi
echo ""
echo "VULNERABLE — Grafana $VERSION is in the affected range for CVE-2026-27877 (upgrade to >= $FIX)"
exit 1- Tenable Plugin 304687
- Grafana Security Advisory — CVE-2026-27877
- Red Hat Bugzilla — CVE-2026-27877
- Grafana Blog — Critical and High Security Fixes (March 2026)
- Grafana GitHub — Direct Access Mode Deprecation (Issue #62270)
- NVD — CVE-2026-27877
- SentinelOne Vulnerability Database — CVE-2026-27877
- AlmaLinux Errata — ALSA-2026:19352
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.