Like handing every office visitor a button that reboots the lobby TV — annoying, not dangerous
CVE-2026-28375 is an uncontrolled resource consumption flaw (CWE-400 / CWE-770) in Grafana's built-in TestData datasource, a core plugin that ships enabled in every Grafana installation since version 8.1.0. Any authenticated user — even one with the lowest Viewer role — can craft a query against the testdata datasource that triggers unbounded memory allocations, causing the Grafana server process to hit an OOM condition and crash. Affected version ranges are massive: 8.1.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.
Grafana's own MEDIUM / 6.5 rating is directionally correct but generous at the score level. The CVSS vector AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H mechanically scores the availability impact as High, but ignores that Grafana processes typically restart within seconds under systemd or container orchestration, making the crash self-healing in most production deployments. There is no confidentiality or integrity impact whatsoever — no data leaks, no code execution, no lateral movement. Tenable's own VPR of 3.0 (Low, 24th percentile) reflects this reality. The EPSS probability is 0.38%, there are no public PoCs, no KEV listing, and zero observed in-the-wild exploitation. We hold the MEDIUM band but compress the score to 5.0 to reflect practical recoverability and the authentication gate.
4 steps from start to impact.
Obtain authenticated Grafana session
Viewer suffices. In enterprises, Grafana is often federated via LDAP, OAuth/OIDC, or SAML, meaning any employee or contractor with SSO access to the monitoring stack has a session. Alternatively, default credentials (admin/admin) on forgotten dev instances provide access.- Valid Grafana credentials or SSO session
- Network access to Grafana HTTP(S) endpoint (typically port 3000)
- Most enterprise Grafana instances sit on internal networks behind VPN or zero-trust gateways
- Internet-exposed instances (~46K on Shodan) are a minority and increasingly protected by WAF or IP allowlists
- MFA on SSO reduces credential-stuffing viability
Craft unbounded testdata query
grafana-testdata-datasource with parameters that cause unbounded memory allocation. The testdata datasource is a core plugin — no additional configuration or plugin installation is required. The exact payload involves requesting a scenario that generates an arbitrarily large in-memory dataset. No specialized tooling is needed; the Grafana Explore UI or a direct API call to /api/ds/query suffices.- Testdata datasource accessible (default: yes, core plugin)
- User has permission to execute datasource queries (Viewer role or above)
- Organizations that have hardened Grafana may have restricted datasource query permissions via RBAC (Grafana Enterprise feature)
- Rate limiting or query timeout configurations can bound the allocation window
- Resource limits (cgroups, Kubernetes memory limits) will OOM-kill the container but prevent host-wide impact
Grafana process crashes (OOM)
- Grafana process memory is not bounded by cgroup/container limits below the crash threshold
- systemd
Restart=alwaysor KubernetesrestartPolicy: Alwaysbrings the service back in seconds - Grafana Alerting evaluation may be handled by a separate process or external Alertmanager, limiting blast radius
- HA deployments behind a load balancer survive a single-node crash
/api/health) returns 503 during downtime. Uptime monitors and synthetic checks catch this immediately.Temporary observability blindness
- Attacker maintains authenticated session across restarts
- No rate limiting or query restriction blocks repeated exploitation
- Alerting pipelines (Alertmanager, PagerDuty, OpsGenie) operate independently of Grafana UI availability
- Security teams typically don't use Grafana as their primary SIEM — Splunk, Elastic, Sentinel continue operating
- Repeated crashes will generate obvious log noise, accelerating incident detection
The supporting signals.
| In-the-Wild Exploitation | None observed. Not listed in CISA KEV. No campaigns or threat actor usage reported as of 2026-09-21. |
|---|---|
| Proof-of-Concept | No public PoC available. No exploit code on GitHub, Exploit-DB, or researcher blogs. The attack is conceptually simple (craft a large testdata query) but no weaponized tooling exists. |
| EPSS Score | 0.00376 (0.38%) — bottom quartile, indicating very low probability of exploitation in the next 30 days. |
| CISA KEV Status | Not listed. CISA ADP assessment marks exploitation as "none" and automatable as "no". |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H — Network-accessible, low complexity, requires low-privilege auth, availability-only impact. No scope change. |
| Tenable VPR | 3.0 (Low) — 23.72nd percentile. Tenable's risk-based scoring significantly discounts this below the CVSS base score. |
| Affected Versions | Grafana 8.1.0 through 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. Extremely wide range — nearly every Grafana release since August 2021. |
| Fixed Versions | 11.6.14, 12.1.10, 12.2.8, 12.3.6, 12.4.2. No distro backport data available yet for Debian/Ubuntu/RHEL packages. |
| Internet Exposure | Shodan indexes ~46,000 Grafana instances on the public internet (2025–2026 data). Most enterprise deployments are internal-only, but shadow IT and dev instances frequently leak. |
| Disclosure Timeline | Published 2026-03-27 by Grafana Labs. Tenable plugin 304689 released 2026-04-02. Patch available same day as advisory. |
Why this verdict
- Authentication gate: PR:L means every attacker must first hold valid Grafana credentials. Anonymous exploitation is impossible. This immediately narrows the threat population to insiders, compromised-credential scenarios, or post-initial-access adversaries.
- DoS-only, self-healing impact: The CVSS A:H rating describes a process crash, not a persistent outage. Grafana under systemd or Kubernetes restarts in seconds. There is zero confidentiality or integrity impact — no data exfiltration, no code execution, no lateral movement. The practical availability impact is a brief dashboard flicker, not a service-destroying event.
- Zero exploitation interest: EPSS 0.38%, no PoC, no KEV listing, no in-the-wild sightings in nearly six months since disclosure. Attackers with valid Grafana credentials have far more valuable options (query real datasources, exfiltrate dashboard data, pivot via SSRF in data source proxies) than crashing the UI.
- Role multiplier: Grafana occupies the *observability/visualization layer*, adjacent to but not part of the SIEM/detection plane. (a) On dev/test instances — negligible impact. (b) On typical internal monitoring — brief dashboard outage, alerting pipelines (Alertmanager, PagerDuty) continue independently. (c) On high-value observability stacks — a temporary Grafana outage does NOT disable alert evaluation or notification delivery in well-architected deployments. Blast radius is host-level (single Grafana process), not tenant/domain/fleet-scale. This does not trigger the HIGH floor because the worst-case outcome is temporary visibility loss, not domain takeover, data egress, or supply-chain compromise.
- Wide version range increases patch surface but not urgency: Every Grafana since 8.1.0 (Aug 2021) is affected, meaning most orgs have vulnerable instances. However, the low exploitability and DoS-only impact make this a scheduled patch, not an emergency.
Why not higher?
Elevating to HIGH would require either (a) a path to code execution or data compromise, (b) evidence of active exploitation, or (c) a blast radius that reaches domain/fleet/supply-chain scale. None apply here. The vulnerability is DoS-only against a visualization layer, requires authentication, and is self-healing. The observability-plane role does not meet the HIGH floor because Grafana's crash does not disable independent alerting pipelines.
Why not lower?
Dropping to LOW would underweight the fact that the testdata datasource is enabled by default in every Grafana installation, the version range spans five years of releases, and ~46K instances are internet-exposed. An authenticated insider or compromised-credential attacker can trivially crash the service with a single API call. The 6.5 base score's A:H component is mechanically earned — the availability impact is real, just recoverable. MEDIUM at a compressed 5.0 score properly reflects the practical risk.
What to do — in priority order.
- Set memory limits on the Grafana process — Configure cgroup memory limits (systemd
MemoryMax=or Kubernetesresources.limits.memory) to cap Grafana at a sane ceiling (e.g., 2–4 GB). This ensures the OOM kill is fast, contained, and doesn't starve co-located services. Deploy within the 365-day noisgate remediation window alongside the patch, or sooner if you have exposed instances. - Restrict testdata datasource access via RBAC — In Grafana Enterprise, use RBAC to deny query permissions on the
grafana-testdata-datasourcefor all roles except Admins. In OSS Grafana, remove or disable the testdata datasource instance if it's not needed — most production deployments don't use it. This eliminates the attack surface entirely. - Enable query timeouts and rate limiting — Set
dataproxy.timeoutand query concurrency limits ingrafana.inito bound runaway queries. Pair with a reverse proxy (nginx, Envoy) that enforces per-user request rate limits on/api/ds/query. This makes sustained DoS via repeated crashes impractical. - Ensure automatic restart is configured — Verify Grafana runs under a supervisor that restarts on crash —
Restart=alwaysin the systemd unit, orrestartPolicy: Alwaysin Kubernetes. This is standard but worth confirming. Recovery time should be <10 seconds. - Deploy Grafana in HA mode — Run multiple Grafana replicas behind a load balancer. A single-node OOM crash doesn't take down the service. This is a best practice for production observability stacks regardless of this CVE.
- WAF rules — the malicious payload is a legitimate-looking datasource query over the standard Grafana API. No WAF signature can distinguish a "too large" testdata request from normal usage without deep application-layer understanding.
- Network segmentation alone — while limiting Grafana to internal networks reduces the attacker pool, the threat model here is an authenticated insider or post-compromise adversary already on the internal network. Segmentation doesn't help against those actors.
- Disabling the testdata plugin entirely via config — the testdata datasource is a core plugin, not an external one. You can prevent loading the bundled version by setting
[plugin.grafana-testdata-datasource] as_external = truewithout providing an external binary, but this is fragile and may break in upgrades. Deleting the datasource instance via API is more reliable.
Crowdsourced verification payload.
Run this script on the Grafana host (or any host that can reach the Grafana API) as any user. It queries the Grafana health and build-info endpoints — no authentication required for version detection. Usage: bash check_cve_2026_28375.sh https://grafana.internal:3000
#!/usr/bin/env bash
# check_cve_2026_28375.sh — Detect CVE-2026-28375 (Grafana testdata OOM DoS)
# Usage: bash check_cve_2026_28375.sh <GRAFANA_URL>
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN
set -euo pipefail
GRAFANA_URL="${1:?Usage: $0 <GRAFANA_URL>}"
GRAFANA_URL="${GRAFANA_URL%/}"
# Fetch version from build info endpoint (unauthenticated)
RESPONSE=$(curl -sf --max-time 10 "${GRAFANA_URL}/api/health" 2>/dev/null || true)
if [[ -z "$RESPONSE" ]]; then
echo "UNKNOWN — could not reach ${GRAFANA_URL}/api/health"
exit 2
fi
VERSION=$(echo "$RESPONSE" | grep -oP '"version"\s*:\s*"\K[0-9]+\.[0-9]+\.[0-9]+' || true)
if [[ -z "$VERSION" ]]; then
# Try /api/frontend/settings as fallback
RESPONSE2=$(curl -sf --max-time 10 "${GRAFANA_URL}/api/frontend/settings" 2>/dev/null || true)
VERSION=$(echo "$RESPONSE2" | grep -oP '"buildInfo".*?"version"\s*:\s*"\K[0-9]+\.[0-9]+\.[0-9]+' || true)
fi
if [[ -z "$VERSION" ]]; then
echo "UNKNOWN — could not extract Grafana version from ${GRAFANA_URL}"
exit 2
fi
echo "Detected Grafana version: ${VERSION}"
# Parse version components
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"
# Version comparison logic
# Vulnerable ranges:
# 8.1.0 <= v < 11.6.14
# 12.0.0 <= v < 12.1.10
# 12.2.0 <= v < 12.2.8
# 12.3.0 <= v < 12.3.6
# 12.4.0 <= v < 12.4.2
VULNERABLE=false
if (( MAJOR >= 8 && MAJOR <= 11 )); then
if (( MAJOR == 8 && MINOR == 0 )); then
VULNERABLE=false # 8.0.x not affected (starts at 8.1.0)
elif (( MAJOR == 11 && MINOR == 6 && PATCH >= 14 )); then
VULNERABLE=false # 11.6.14+ is patched
elif (( MAJOR == 8 )) && (( MINOR >= 1 )); then
VULNERABLE=true
elif (( MAJOR >= 9 && MAJOR <= 10 )); then
VULNERABLE=true
elif (( MAJOR == 11 )); then
if (( MINOR < 6 )); then
VULNERABLE=true
elif (( MINOR == 6 && PATCH < 14 )); then
VULNERABLE=true
fi
fi
elif (( MAJOR == 12 )); then
if (( MINOR == 0 )); then
VULNERABLE=true # 12.0.x has no fix in the 12.0 branch
elif (( MINOR == 1 )); then
if (( PATCH < 10 )); then
VULNERABLE=true
fi
elif (( MINOR == 2 )); then
if (( PATCH < 8 )); then
VULNERABLE=true
fi
elif (( MINOR == 3 )); then
if (( PATCH < 6 )); then
VULNERABLE=true
fi
elif (( MINOR == 4 )); then
if (( PATCH < 2 )); then
VULNERABLE=true
fi
fi
fi
if $VULNERABLE; then
echo "VULNERABLE — Grafana ${VERSION} is affected by CVE-2026-28375"
echo "Upgrade to 11.6.14, 12.1.10, 12.2.8, 12.3.6, or 12.4.2+"
exit 1
else
echo "PATCHED — Grafana ${VERSION} is not affected by CVE-2026-28375"
exit 0
fiWhat defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.