CVE feed → CVE-2024-9264

CVE-2024-9264 — Grafana SQL Expressions command injection (RCE)

Grafana's experimental SQL Expressions feature (introduced in 11.0) used DuckDB to evaluate queries but left the engine's default trusted extensions enabled — including the system() function. Any authenticated user with the Viewer role or higher could execute arbitrary shell commands on the Grafana host. In homelab installs that typically run Grafana as root in Docker, that's root-level RCE behind a login form many people leave open.

TL;DR

At a glance

CVE IDCVE-2024-9264
SeverityHigh (NVD CVSS 8.8) / Critical (Grafana Labs CVSS 9.9 with S:C)
CVSS vector (NVD)AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
CWECWE-94 (Improper Control of Generation of Code) · CWE-77 (Command Injection)
AdvisoryGHSA-99rg-6q39-mwm6
Published2024-10-17
Affected versionsGrafana 11.0.0–11.0.5, 11.1.0–11.1.6, 11.2.0–11.2.1
Fixed versions11.0.6, 11.1.7, 11.2.2 (and 11.3.0+)
ImpactRCE on Grafana host as the Grafana process user

What goes wrong in SQL Expressions

SQL Expressions is an experimental feature added in Grafana 11.0 that lets dashboard authors run SQL on top of arbitrary data-source results, using DuckDB as the embedded engine. The intent is to give analysts a "join two Prometheus queries and pivot" escape hatch without leaving the dashboard.

DuckDB ships with a set of optional extensions that are marked trusted by default — httpfs, parquet, and crucially the system extension which exposes a system() table function that runs shell commands on the host. DuckDB assumes the caller controls the SQL it's running; that assumption is fine for an analytics CLI, but not for a multi-user web application.

Grafana's SQL Expressions evaluator instantiated DuckDB without restricting which extensions could be installed or loaded. INSTALL and LOAD were reachable from user-supplied SQL, and once system() was available, the query result included whatever the spawned command wrote to stdout. Because evaluation happens inside the Grafana backend process, every shell call inherits Grafana's user, its filesystem view, and its network position behind whatever firewall protects the host.

The authentication bar is the lowest meaningful one Grafana has: the Viewer role. Viewer is the role you grant to "people who should be able to look at dashboards"; it does not grant data-source editing, alerting, or admin. SQL Expressions evaluation runs as part of the query pipeline that Viewer is allowed to drive, which is how a read-only role became a remote shell.

Affected versions and fix paths

Match your installed Grafana version against the vulnerable column; upgrade to the fixed column on the same release line, or move to 11.3+.

Release line Vulnerable Fixed in
Grafana 11.0.x11.0.0 – 11.0.511.0.6
Grafana 11.1.x11.1.0 – 11.1.611.1.7
Grafana 11.2.x11.2.0 – 11.2.111.2.2
Grafana 11.3+Not affected — feature gated by defaultn/a
Grafana 10.x and earlierFeature did not exist — not affectedn/a

Quick scan check

Run one of these on each host that runs Grafana. The goal is to identify the running version and whether the sqlExpressions feature toggle is enabled.

# Docker container
docker exec grafana grafana-server -v

# Bare metal (systemd / Debian / Ubuntu)
grafana-server -v
dpkg -l grafana 2>/dev/null | awk '/^ii/ {print $2, $3}'

# Bare metal (RHEL family)
rpm -q grafana

# Over the network (no shell required)
curl -s http://your-grafana:3000/api/health

# Check whether the vulnerable feature is enabled
grep -E 'sqlExpressions|feature_toggles' /etc/grafana/grafana.ini

If the version starts with 11.0., 11.1. or 11.2. and is below the matching fix in the table above, the host is exposed whenever the SQL Expressions toggle is enabled. The /api/health endpoint returns a JSON object with the version string and does not require authentication on most installs.

Mitigations beyond patching

Why this matters more in homelabs than enterprises

Enterprise Grafana installs almost always sit behind SSO, with role assignments synced from an IdP and network reachability restricted to a corporate VPN. Compromising a Viewer account requires getting past the IdP, and even then the Grafana host usually lives in a segment with no outbound internet and a restrictive egress policy.

Homelab Grafana is a different shape. It's typically on the shared homelab LAN, reachable from anything else on that LAN — including a guest WiFi if the segmentation is loose. Auth is often a single shared password, sometimes the default admin / admin from the initial setup that never got changed. Many self-hosters expose Grafana through a reverse proxy with no extra auth layer because it has its own login. That model is fine when the login is the only attack surface — it stops working the moment a Viewer account is sufficient for RCE.

The result is a population where the patching gap and the auth-strength gap multiply: see the patching gap on self-hosted services for how long these windows tend to stay open in practice.

What Noxen does about this

Noxen flags Grafana's web UI as an exposed admin surface whenever it's reachable on a host you've enrolled, and matches CVE-2024-9264 against the installed Grafana package version across your fleet. If a host runs Grafana 11.0.0–11.2.1 below the matching fix line, you get a finding with the affected version, the fix version, and the upgrade path — alongside the admin-surface flag that tells you whether the login page is actually reachable.

Authoritative sources

See what Noxen does about CVEs like this →   Back to the CVE feed →