Like a hotel manager whose master key works on every floor — but they already had to be staff to get a key at all
CVE-2026-21721 is a broken access-control bug in Grafana's dashboard permissions API. The endpoint that manages per-dashboard ACLs checks only that the caller holds the dashboards.permissions:* action — it never validates that the caller is actually authorized *for the specific dashboard being modified*. An authenticated user who legitimately manages permissions on Dashboard A can therefore read and rewrite permissions on Dashboards B through Z. Affected versions span 10.2.0 through 11.6.8, 12.0.0–12.0.7, 12.1.0–12.1.4, 12.2.0–12.2.2, and 12.3.0. Patched releases are 11.6.9+security-01, 12.0.8+security-01, 12.1.5+security-01, 12.2.3+security-01, and 12.3.1+security-01.
Grafana and Red Hat both stamp this HIGH / 8.1, but the CVSS score overweights the theoretical ceiling and ignores the prerequisite chain. The vector AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N counts PR as Low, yet the *actual* prerequisite is not merely 'any authenticated user' — it's a user who already holds the dashboards.permissions:* action on at least one dashboard. In most orgs that population is dashboard admins and Grafana Org Admins, i.e., a small, already-privileged cohort. The impact is confined to dashboard ACL manipulation within one Grafana organization — not RCE, not data-source credential theft, not system compromise. With no public PoC, no KEV listing, no in-the-wild activity, and an EPSS of 0.67% (49th percentile), the vendor severity is materially inflated.
5 steps from start to impact.
Obtain authenticated Grafana session
- Valid Grafana user credentials or API key
- Network reachability to the Grafana HTTP(S) port (default 3000)
- Enterprise Grafana is usually behind SSO/MFA via OAuth or SAML — credential theft is non-trivial
- Many deployments are internal-only, not internet-facing
Hold dashboards.permissions:* action on at least one dashboard
dashboards.permissions:read and dashboards.permissions:write actions. These are NOT granted to Viewers or basic Editors by default — they're assigned to Dashboard Admins, Folder Admins, or Org Admins. The attacker must already occupy one of these roles to enter the vulnerable code path.- User role includes
dashboards.permissions:*on ≥1 dashboard - Grafana RBAC is configured (default on 10.x+)
- Default Viewer and Editor roles lack this action entirely
- In large orgs, only a handful of power users or automation service accounts hold dashboard-admin permissions
- Org Admin accounts are typically tightly controlled
PATCH /api/dashboards/:uid/permissions calls are detectableEnumerate target dashboard UIDs
/api/search endpoint, which returns dashboards the caller can see. Even without direct view access, dashboard titles and UIDs may be enumerable depending on folder permissions.- Authenticated session from Step 1
- Some level of search/browse access
- Folder-level ACLs may limit dashboard discovery
- Grafana audit logs capture search API usage
/api/search calls or sequential dashboard enumeration in access logsModify permissions on out-of-scope dashboards
POST /api/dashboards/:uid/permissions targeting a dashboard UID they do NOT legitimately manage. Because the API only checks for the dashboards.permissions:* action globally and not against the specific dashboard, the request succeeds. The attacker can grant themselves Viewer or Editor access on the target dashboard, or grant access to a collaborator account.- Steps 1–3 completed
- Target dashboard UID known
- Permission change is logged in Grafana's audit trail (Enterprise edition)
- Grafana alerting on permission-change events can trigger near-real-time notification
- The attacker is modifying ACLs, not directly exfiltrating data — a second step is needed to view dashboard content
dashboards.permissions API calls across different dashboard scopesAccess sensitive dashboard content
- Permission modification from Step 4 succeeded
- Dashboard contains data of value to the attacker
- Dashboard data is observability metrics, not typically PII or regulated data
- Data-source credentials remain hidden behind Grafana's secret store — this vuln does NOT expose them
- Impact requires the target dashboards to contain meaningfully sensitive information
The supporting signals.
| In-the-Wild Exploitation | No evidence. Not listed in CISA KEV. No vendor, CERT, or threat-intel reports of active exploitation as of September 2026. |
|---|---|
| Proof-of-Concept | None public. No PoC repositories (nomi-sec/PoC-in-GitHub, SecureWithUmer/CVE-2026-PoCs) index a working exploit. The API call is trivial to construct but requires authenticated, privileged access. |
| EPSS | 0.67% (49th percentile) — below the median exploitation probability, consistent with the auth-gated, narrow-prerequisite profile. |
| CISA KEV | Not listed as of 2026-09-22. |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N — Network-attackable, low complexity, low privilege, no user interaction. C:H and I:H reflect dashboard-ACL read/write. A:N because no denial-of-service path exists. |
| Affected Versions | 10.2.0–11.6.8, 12.0.0–12.0.7, 12.1.0–12.1.4, 12.2.0–12.2.2, 12.3.0 |
| Fixed Versions | 11.6.9+security-01, 12.0.8+security-01, 12.1.5+security-01, 12.2.3+security-01, 12.3.1+security-01. Red Hat backports: RHSA-2026:2914, RHSA-2026:2920, RHSA-2026:3078, RHSA-2026:3529, RHSA-2026:5633, RHSA-2026:8229. |
| Internet Exposure | ~600,000+ Grafana instances internet-reachable per ZoomEye scans. Shodan indexes ~5,000+ via default port 3000. However, exploitation requires *authenticated, permission-privileged* access — raw exposure count is misleading for this CVE. |
| Disclosure | Published 2026-01-27 by Grafana Labs. Discovered by researcher se1en via Grafana's bug bounty program. |
| Vendor Advisories | Grafana SA, Red Hat CVE, Tenable Plugin 297197 |
Why this verdict
- Authentication gate: The entire chain requires a valid, authenticated Grafana session. In enterprise deployments with SSO/MFA, obtaining this is non-trivial and implies the attacker is already an insider or has compromised credentials through a separate vector.
- Narrow privilege prerequisite: The vulnerable code path is only reachable by users holding
dashboards.permissions:*— a privilege typically restricted to Dashboard Admins, Folder Admins, or Org Admins. This is NOT a default Viewer or Editor capability. The realistic attacker population is a small fraction of the user base. - Impact ceiling is dashboard ACLs, not system compromise: The worst outcome is reading and modifying *dashboard permissions* within one Grafana organization. There is no path to RCE, no data-source credential exposure, no lateral movement, and no availability impact. The CVSS C:H/I:H ratings describe the dashboard-permission scope, not system-level impact.
- No exploitation pressure: Zero public PoCs, zero KEV listing, zero in-the-wild reports after 8 months of disclosure. EPSS at 0.67% (49th percentile) confirms low predicted exploitation probability.
- Role multiplier: Grafana is an observability platform, not canonically a high-value-role component (not an IdP, hypervisor, PAM, CA, CI/CD, backup engine, kernel-mode agent, or network edge appliance). In its typical deployment role — monitoring dashboards for engineering and ops teams — the blast radius of dashboard ACL manipulation is *organization-internal, data-plane-only*. Even in a high-value deployment (e.g., Grafana monitoring a SOC's security metrics), the chain succeeds only for already-privileged dashboard admins and the outcome is dashboard-level visibility, not domain takeover, fleet compromise, or supply-chain pivot. This does not meet the HIGH floor criteria.
Why not higher?
Upgrading to HIGH would require either active exploitation, a public weaponized PoC, or a blast radius that reaches fleet/domain/identity-scale compromise. None of these conditions are met. The vulnerability is entirely confined to dashboard ACL manipulation within one Grafana org, requires an already-privileged authenticated user, and has generated zero exploitation interest in 8 months. The 600k+ internet-exposed Grafana instances are irrelevant because this is not an unauth bug.
Why not lower?
Downgrading to LOW would underweight the real risk that a malicious insider with dashboard-admin rights can silently escalate visibility across an entire Grafana organization's dashboards. In environments where Grafana monitors sensitive infrastructure (production databases, cloud spend, security alerts), unauthorized dashboard access has meaningful confidentiality impact. The attack is also trivial to execute for someone who already holds the prerequisite permissions — no exploit development required, just an API call.
What to do — in priority order.
- Audit and minimize dashboards.permissions:* grants — Review Grafana RBAC assignments and remove
dashboards.permissions:writefrom any user or service account that does not strictly need it. This directly eliminates the attacker population for this CVE. Complete within the 365-day noisgate remediation SLA window, but start immediately as it's good hygiene regardless. - Enable Grafana Enterprise audit logging — If running Grafana Enterprise, enable the audit log and forward
dashboards.permissionschange events to your SIEM. This provides detection coverage for exploitation attempts until the patch is applied. - Restrict Grafana network exposure — Ensure Grafana is not directly internet-facing. Place it behind a reverse proxy with SSO/MFA enforcement. While this CVE requires authentication, reducing the attack surface limits credential-stuffing and token-theft vectors that could feed into this chain.
- Apply the vendor patch within 365 days — Update to 11.6.9+security-01, 12.0.8+security-01, 12.1.5+security-01, 12.2.3+security-01, or 12.3.1+security-01 depending on your release train. As a MEDIUM-severity finding with no mitigation SLA, go straight to the remediation window. RHEL users can apply the relevant RHSA errata (2026:2914, 2026:3078, etc.).
- WAF rules — The exploit uses legitimate Grafana API endpoints with valid authentication tokens. No WAF signature can distinguish a legitimate permission change from an out-of-scope one; the authorization logic is server-side.
- Network segmentation alone — Segmenting Grafana from the internet helps, but the attacker population is *authenticated insiders with dashboard-admin rights*. Network controls don't address insider threat.
- Rotating Grafana admin passwords — The vulnerability doesn't require Org Admin or Grafana Server Admin credentials. It's exploitable by any user with
dashboards.permissions:*on a single dashboard, which is a much lower bar than admin access.
Crowdsourced verification payload.
Run this on your Grafana server or any host with curl and network access to the Grafana API. Invoke as: bash check_cve_2026_21721.sh https://grafana.example.com. No authentication required — it queries the unauthenticated /api/health endpoint for version info.
#!/usr/bin/env bash
# check_cve_2026_21721.sh — Detect CVE-2026-21721 (Grafana dashboard permissions scope bypass)
# Usage: bash check_cve_2026_21721.sh <GRAFANA_BASE_URL>
# Exit codes: 0=VULNERABLE, 1=PATCHED, 2=UNKNOWN
set -euo pipefail
GRAFANA_URL="${1:-}"
if [[ -z "$GRAFANA_URL" ]]; then
echo "Usage: $0 <GRAFANA_BASE_URL>"
echo "Example: $0 https://grafana.example.com"
exit 2
fi
# Strip trailing slash
GRAFANA_URL="${GRAFANA_URL%/}"
# Fetch version from health endpoint
VERSION=$(curl -sk --max-time 10 "${GRAFANA_URL}/api/health" 2>/dev/null | grep -oP '"version"\s*:\s*"\K[^"]+' || true)
if [[ -z "$VERSION" ]]; then
echo "UNKNOWN — Could not retrieve Grafana version from ${GRAFANA_URL}/api/health"
exit 2
fi
echo "Detected Grafana version: $VERSION"
# Strip +security-01 or similar suffixes for comparison, but note their presence
HAS_SECURITY_SUFFIX=0
if [[ "$VERSION" == *"+security"* ]]; then
HAS_SECURITY_SUFFIX=1
fi
# Extract base version (strip everything after +)
BASE_VERSION=$(echo "$VERSION" | sed 's/+.*//')
# Version comparison function
ver() { printf '%03d%03d%03d' $(echo "$1" | tr '.' ' '); }
V=$(ver "$BASE_VERSION")
# Check affected ranges:
# 10.2.0 - 11.6.8 → fixed in 11.6.9+security-01
# 12.0.0 - 12.0.7 → fixed in 12.0.8+security-01
# 12.1.0 - 12.1.4 → fixed in 12.1.5+security-01
# 12.2.0 - 12.2.2 → fixed in 12.2.3+security-01
# 12.3.0 → fixed in 12.3.1+security-01
VULNERABLE=0
if [[ $V -ge $(ver "10.2.0") && $V -le $(ver "11.6.8") ]]; then
VULNERABLE=1
elif [[ $V -eq $(ver "11.6.9") && $HAS_SECURITY_SUFFIX -eq 0 ]]; then
# 11.6.9 without +security-01 may still be vulnerable
VULNERABLE=1
elif [[ $V -ge $(ver "12.0.0") && $V -le $(ver "12.0.7") ]]; then
VULNERABLE=1
elif [[ $V -eq $(ver "12.0.8") && $HAS_SECURITY_SUFFIX -eq 0 ]]; then
VULNERABLE=1
elif [[ $V -ge $(ver "12.1.0") && $V -le $(ver "12.1.4") ]]; then
VULNERABLE=1
elif [[ $V -eq $(ver "12.1.5") && $HAS_SECURITY_SUFFIX -eq 0 ]]; then
VULNERABLE=1
elif [[ $V -ge $(ver "12.2.0") && $V -le $(ver "12.2.2") ]]; then
VULNERABLE=1
elif [[ $V -eq $(ver "12.2.3") && $HAS_SECURITY_SUFFIX -eq 0 ]]; then
VULNERABLE=1
elif [[ $V -eq $(ver "12.3.0") ]]; then
VULNERABLE=1
fi
if [[ $VULNERABLE -eq 1 ]]; then
echo "VULNERABLE — Grafana $VERSION is affected by CVE-2026-21721"
echo "Upgrade to the corresponding +security-01 release for your branch."
exit 0
else
echo "PATCHED — Grafana $VERSION is not affected by CVE-2026-21721"
exit 1
fiWhat defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.