Your dashboards became a credential vault, and one buggy SQL expression opens it
Tenable plugin 316482 bundles the March/May 2026 Grafana security releases. The headline flaw is CVE-2026-27876 — a SQL Expressions arbitrary-file-write that chains through a Grafana Enterprise plugin into full RCE on the Grafana host, including SSH-key writes. The companion issue is CVE-2026-27880, an unauthenticated memory-exhaustion DoS via the OpenFeature endpoint. Additional bugs in the same release train (CVE-2026-28374/76/79/80/83, CVE-2026-33376–33381) cover public-dashboard secret leaks and missing protected-field authorization. Affected: Grafana 11.6.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: 11.6.14+security-04, 12.1.10, 12.2.8+security-04, 12.3.6+security-04, 12.4.3+security-02, 13.0.1+security-01.
Grafana labels this HIGH (CVSS 9.1 on the RCE component) and that's a defensible call rather than an inflated one. The RCE requires *three* stacked prerequisites — the sqlExpressions feature toggle enabled, a Grafana Enterprise license with the vulnerable datasource plugin, and at least Viewer credentials on a datasource — but Grafana is a role multiplier: the box holds datasource credentials for Prometheus, Loki, cloud accounts, prod databases, and Kubernetes clusters. Fleet-wide, a compromised Grafana is a credential piñata, which is why we hold the verdict at HIGH rather than downgrading on friction alone.
5 steps from start to impact.
Obtain Viewer-or-higher credentials on the Grafana instance
- Grafana reachable from attacker's network position
- Viewer/Editor/Admin credential OR anonymous access enabled
- Most enterprise Grafanas sit behind SSO with restricted auto-provisioning
- Anonymous access is off by default in modern deployments
grafana.log; SIEM correlation on new user + immediate datasource queryConfirm sqlExpressions toggle + Enterprise plugin present
sqlExpressions feature toggle and requires a specific Grafana Enterprise datasource plugin to complete the chain. Attackers enumerate via /api/frontend/settings and /api/plugins. OSS-only deployments are not exploitable for RCE.sqlExpressionsfeature flag enabled- Grafana Enterprise + vulnerable datasource plugin installed
- OSS installs (majority of internet-exposed) lack the Enterprise plugin
- Feature toggle is off by default in older 11.x lines
feature_toggles.enable = sqlExpressions; plugin inventory via /api/pluginsCraft SQL expression that writes to arbitrary path
authorized_keys file under the grafana user, or a datasource config that shells out on next load. Public PoC has not surfaced on GitHub as of this writing but the Grafana blog explicitly documents both primitives.- Step 2 satisfied
- Filesystem write reachable by grafana process UID
- Containerized deployments with read-only rootfs block the SSH-key path
- AppArmor/SELinux profiles on distro packages constrain write locations
/var/lib/grafana, /usr/share/grafana/plugins, ~grafana/.sshTrigger code execution and pivot to credential store
grafana.db (SQLite) or the external DB — datasource credentials are encrypted with a static secret in grafana.ini that's also on-host. Cloud API keys, Prometheus basic-auth, and database creds fall out. Tooling: sqlite3 + custom decrypt scripts published against Grafana's securejsondata format.- Step 3 landed
- Access to grafana.db or configured external DB
- Vault-backed datasource secrets (Grafana OSS 10+ envvar refs) contain the blast
- Read-only container filesystems limit persistence
grafana-server; egress alerts on datasource-configured cloud endpoints from the Grafana hostParallel/alternate: unauth DoS via OpenFeature (CVE-2026-27880)
- Grafana 12.1.0–12.4.1 reachable
- WAF request-size limits (>1MB body) blunt naive payloads
- Autoscaling / systemd restart masks impact
/api/featuremgmt/*The supporting signals.
| In-the-wild status | No confirmed exploitation as of 2026-07-23; not on CISA KEV |
|---|---|
| Public PoC | None public on GitHub for CVE-2026-27876 chain; Grafana blog details primitives but withholds working exploit |
| EPSS | ~0.7% (percentile ~65) — moderate, reflects auth+toggle prerequisites |
| KEV | Not listed |
| CVSS v3.1 (RCE) | 9.1 CRITICAL — AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H (vendor rates HIGH per blog title despite 9.1 score) |
| CVSS v3.1 (DoS) | 7.5 HIGH — AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H |
| Affected versions | 11.6.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+security-04, 12.1.10, 12.2.8+security-04, 12.3.6+security-04, 12.4.3+security-02, 13.0.1+security-01; Red Hat backport in RHSA-2026:7011 |
| Exposure (Shodan/Censys) | ~110k Grafana instances internet-facing per Shodan HTTP title fingerprint; majority OSS, minority Enterprise-licensed |
| Disclosure / reporter | Grafana security release 2026-03-25 (blog); Tenable plugin 316482; CVE-2026-27876 credited to internal Grafana security team |
noisgate verdict.
Verdict held at HIGH because the RCE chain requires the sqlExpressions feature toggle and an Enterprise plugin and Viewer credentials — three stacked prerequisites that narrow the exploitable population to a minority of installs. What prevents a downgrade to MEDIUM is the role multiplier: a compromised Grafana host is a credential vault for the observability plane (cloud API keys, prod DB creds, K8s tokens), so successful exploitation ends in lateral compromise, not just a dashboard defacement.
Why this verdict
- Prerequisite stacking: RCE demands Enterprise license + vulnerable plugin +
sqlExpressionstoggle + Viewer creds. Each condition strips exploitable population — combined <10% of Grafana installs qualify. - Role multiplier: Grafana is *the* observability control plane; the process holds datasource creds for prod DBs, cloud accounts, Prometheus, Loki, K8s. RCE here = credential harvest, not a contained dashboard box. Floor stays HIGH.
- Unauth surface exists but bounded: CVE-2026-27880 is a memory-exhaust DoS, not RCE — bad but recoverable behind autoscaling / systemd restart.
- No active exploitation, no KEV, no public PoC — removes the CRITICAL upgrade pressure that would apply if a weaponized chain were circulating.
- Widespread deployment: ~110k internet-facing instances per Shodan; even 5% Enterprise + toggle share equals thousands of exploitable targets, keeping the aggregate risk material.
Why not higher?
No public PoC, no KEV listing, no observed exploitation, and the RCE requires an Enterprise-licensed plugin plus a non-default feature toggle plus valid credentials. Under noisgate rules a CRITICAL floor requires either canonical high-value-role status alone with a working chain, active exploitation, or an unauthenticated primitive with RCE impact — none present here.
Why not lower?
Grafana's role as observability + datasource-credential store means a landed RCE cascades into cloud/DB/K8s credential theft, not just a defaced dashboard. The unauthenticated DoS primitive (CVE-2026-27880) also raises the aggregate floor above MEDIUM even for OSS-only deployments.
What to do — in priority order.
- Disable the
sqlExpressionsfeature toggle — Editgrafana.inior config-map and removesqlExpressionsfromfeature_toggles.enable. Restart the service. This alone kills the RCE primitive without touching the binary. Deploy within 30 days per noisgate HIGH mitigation SLA — or within hours if the instance is internet-facing. - Restrict Grafana network exposure — Move all Grafana instances behind an SSO-authenticated reverse proxy (oauth2-proxy, Cloudflare Access, Tailscale). No Grafana should terminate TLS on the public internet. Blocks anonymous DoS and reduces credential-brute surface. Same 30-day window.
- Rotate all datasource credentials post-patch — Assume any pre-patch RCE would have exfiltrated the on-disk secret key +
grafana.db. After upgrading, rotate every datasource credential, API key, and service-account token stored in Grafana. Complete within the 30-day mitigation window. - Enforce request-size limits at the proxy — Add
client_max_body_size 256k;(nginx) or equivalent Envoy/HAProxy rule for/api/featuremgmt/*and/api/frontend/settingsto blunt CVE-2026-27880 memory-exhaust payloads until patched. - Audit anonymous and auto-provisioned access — Set
[auth.anonymous] enabled = falseand disableauto_assign_org_roleor set it to a no-datasource-access role. Removes the easiest path to Viewer-tier creds needed for the RCE chain.
- WAF signatures — the malicious SQL Expression payload is legitimate Grafana API traffic to a legitimate endpoint; no signature reliably discriminates.
- Read-only container filesystem alone — helpful against SSH-key persistence but the AWS-datasource-config write primitive still executes code on next plugin load if the config dir is writable.
- Downgrading to Grafana OSS — the DoS (CVE-2026-27880) and public-dashboard secret leaks still apply; only the Enterprise-plugin RCE goes away.
Crowdsourced verification payload.
Run on the Grafana host itself with sudo (needs read on /etc/grafana/grafana.ini and the binary). Invoke: sudo bash check_grafana_316482.sh. Also usable against a remote instance with GRAFANA_URL=https://grafana.example.com API_TOKEN=glsa_xxx bash check_grafana_316482.sh for the version-only check.
#!/usr/bin/env bash
# noisgate check for Tenable 316482 / Grafana security release 2026-03/05
# Exit codes: 0 PATCHED, 1 VULNERABLE, 2 UNKNOWN
set -u
STATUS="UNKNOWN"
DETAIL=""
version_lt() {
# returns 0 if $1 < $2 (semver-ish, ignores +build metadata)
[ "$1" = "$2" ] && return 1
printf '%s\n%s\n' "$1" "$2" | sort -V -C && return 1 || return 0
}
get_version_local() {
if command -v grafana-server >/dev/null 2>&1; then
grafana-server -v 2>&1 | awk '/Version/ {print $2; exit}'
elif [ -x /usr/sbin/grafana-server ]; then
/usr/sbin/grafana-server -v 2>&1 | awk '/Version/ {print $2; exit}'
fi
}
get_version_remote() {
[ -z "${GRAFANA_URL:-}" ] && return 1
curl -sk -H "Authorization: Bearer ${API_TOKEN:-}" \
"${GRAFANA_URL%/}/api/health" | grep -oE '"version":"[^"]+"' | cut -d\" -f4
}
VER="$(get_version_local || true)"
[ -z "$VER" ] && VER="$(get_version_remote || true)"
VER="${VER%%+*}" # strip +security-XX metadata
if [ -z "$VER" ]; then
echo "UNKNOWN: could not determine Grafana version"
exit 2
fi
# Fixed baselines per branch
case "$VER" in
11.6.*) FIX="11.6.14" ;;
12.0.*|12.1.*) FIX="12.1.10" ;;
12.2.*) FIX="12.2.8" ;;
12.3.*) FIX="12.3.6" ;;
12.4.*) FIX="12.4.3" ;;
13.0.*) FIX="13.0.1" ;;
*) echo "UNKNOWN: unrecognized branch $VER"; exit 2 ;;
esac
if version_lt "$VER" "$FIX"; then
STATUS="VULNERABLE"
DETAIL="installed=$VER fixed>=$FIX"
else
STATUS="PATCHED"
DETAIL="installed=$VER meets fixed>=$FIX"
fi
# Extra: check if sqlExpressions toggle is enabled (elevates risk)
if [ -r /etc/grafana/grafana.ini ] && grep -Eiq '^[[:space:]]*enable[[:space:]]*=.*sqlExpressions' /etc/grafana/grafana.ini; then
DETAIL="$DETAIL; sqlExpressions=ENABLED (RCE chain reachable if unpatched)"
fi
echo "$STATUS: $DETAIL"
case "$STATUS" in
PATCHED) exit 0 ;;
VULNERABLE) exit 1 ;;
*) exit 2 ;;
esac
If you remember one thing.
sqlExpressions is enabled and whether Enterprise is licensed — that triage tells you which hosts need same-week attention vs which ride the normal cycle. (2) For any internet-facing Grafana or any Enterprise+sqlExpressions instance, apply the compensating controls (disable the toggle, put behind auth proxy) within the noisgate mitigation SLA of 30 days — sooner if exposed. (3) Roll the vendor patch to 11.6.14+security-04 / 12.2.8+security-04 / 12.4.3+security-02 / 13.0.1+security-01 (or the RHSA-2026:7011 backport) inside the noisgate remediation SLA of 180 days. (4) After patching, rotate every datasource credential stored in Grafana — assume pre-patch RCE would have exfiltrated the secret key.Sources
- Grafana advisory — CVE-2026-27876 (sqlExpressions RCE)
- Grafana blog — Critical/High security release
- Grafana 11.6.14+security-04 release notes
- VulDB CVE-2026-28380 (Nessus 316482 / WID-SEC-2026-1546)
- Red Hat RHSA-2026:7011 backport
- Canadian Centre for Cyber Security AV26-285
- Grafana Security Advisories index
- Tenable Nessus plugin family (Grafana)
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.