The SQLite File That Exposed a Monitoring Environment

#02HIGH/ FirewallFables/ Oct 8, 2026/ 6 min read

#Prologue: A Three-Year-Old Bug

CVE-2021-43798 was disclosed in December 2021. It's a directory traversal in Grafana's plugin asset handler. Fix was out in 8.3.0. Metasploit module exists. Every security engineer knows about it.

So naturally, in July 2026, I found a Grafana 8.0.0 still running in production, exposed to the internet.

The path traversal itself was straightforward - the same --path-as-is dance I've described before. Nginx normalized the ../ away. curl's --path-as-is sent the raw path through. Grafana served the file.

/etc/passwd - Alpine, grafana uid 472. Standard container setup.

Then I pulled grafana.ini. Then defaults.ini. Then ldap.toml.

And then I went for the real prize.

#The 7MB Database

Grafana stores everything in a SQLite database at /var/lib/grafana/grafana.db. On this instance, it was 7.1 MB - that's a lot of dashboards.

curl -sk --path-as-is \
"https://grafana.admin.[redacted].com/public/plugins/alertlist/../../../../../../../../../var/lib/grafana/grafana.db" \
-o grafana.db

A multi-megabyte SQLite database from a Grafana instance is the security equivalent of finding a server room with the door unlocked. Grafana databases contain:

  • Dashboard definitions - JSON blobs with embedded queries, panel configurations, and often hardcoded SQL queries that reveal database schemas and business logic
  • Data source configurations - connection strings, hostnames, ports, usernames, and sometimes passwords
  • API keys - Grafana API keys with various permission levels
  • User accounts - email addresses, display names, login information
  • Organization structure - teams, folders, permissions
  • Alert configurations - notification channels, webhook URLs

#What I Found in the DB

#Data Sources (The Good Stuff)

The database contained multiple configured data sources. Among the most significant were:

  • Zabbix - monitoring platform integration:
    • URL: https://noc.[redacted].com/api_jsonrpc.php
    • User: API-grafana-REDACTED
    • Password: REDACTED ← plaintext, in json_data

The password was stored in json_data (plaintext visible to anyone who reads the database) rather than secure_json_data (encrypted with Grafana's secret key). This is a common misconfiguration - developers put credentials in the wrong field and assume they're safe.

  • MS SQL Server:
    • Host: XX.XXX.XX.141:1433
    • Database: REDACTED_grafana

Password was AES-encrypted (Grafana's envelope encryption), but with access to the database I also had the secret key from grafana.ini. Decryption was a few lines of Python away.

  • Prometheus & Elasticsearch - no auth, but knowing the internal hostnames (promethmetrics:8428, elastic-log:9200) maps the internal network topology.

#The Teams Webhook

https://[redacted].webhook.office.com/webhookb2/[...]/IncomingWebhook/[...]

A Microsoft Teams connector webhook for an internal alert channel. Anyone with this URL can post messages to the team's internal channel - perfect for social engineering, fake alerts, or phishing.

#User Accounts

Multiple users with full names and email addresses. These were real accounts, including:

  • Managing directors
  • System administrators
  • External contractors from a consulting firm
  • Monitoring service accounts

Each with their email, organization, and role within Grafana.

#The Pivot: From Grafana to Zabbix

Zabbix is an enterprise monitoring platform. It tracks every server, network device, and application in the infrastructure. The Grafana database handed me a set of Zabbix API credentials in plaintext.

One API call later:

POST https://noc.[redacted].com/api_jsonrpc.php
Content-Type: application/json-rpc
{
"jsonrpc": "2.0",
"method": "user.login",
"params": {
"user": "API-grafana-REDACTED",
"password": "XXXXXXXXXX"
},
"id": 1
}
→ {"result":"4d8c3e82889c99c43d1bf458942b398e"}

Authenticated. With a read-only API user. But "read-only" in Zabbix still gives you:

{
"jsonrpc": "2.0",
"method": "host.get",
"params": {
"output": ["hostid", "host"],
"limit": 5000
},
"auth": "4d8c3e82889c99c43d1bf458942b398e",
"id": 1
}

Several thousand hosts. The API exposed a broad inventory of monitored systems, including servers, network devices, infrastructure components, and other managed assets across the environment.

#The Scale of What Was Exposed

#Numerous Host Groups

Zabbix organizes hosts into groups. Each group represents a logical unit:

  • Managed organizations - multiple organizations, each with their own host groups containing servers, network equipment, and site-specific infrastructure
  • Infrastructure components - event-streaming systems, containerized workloads, object storage, remote-access infrastructure, and other supporting services
  • Geographic locations - multiple sites and network segments

#Numerous Automated Response Actions

When a server goes down, Zabbix doesn't just log it - it acts. The configured actions included:

  • MS Teams notifications - posting to internal channels
  • Email alerts - to distribution lists and on-call engineers
  • Jira ticket creation - automated incident management
  • Slack, Telegram, Discord - redundant notification channels
  • PagerDuty, ServiceNow - enterprise incident response
  • SMS - for critical infrastructure failures
  • Custom scripts - automated remediation and operational tasks executed on monitored hosts

#The SNMP Community String

SNMP community strings are passwords that grant access to network device telemetry. On this Zabbix instance:

{$SNMP_COMMUNITY} = REDACTEDever!

A global macro applied to every SNMP-monitored device. Routers, switches, firewalls, UPS units - all using the same community string. And it's global - applied automatically to new hosts when they're added to monitoring.

SNMP v2c sends community strings in plaintext over UDP. Anyone on the network with packet capture can see it. And now, anyone who read this report has it.

#The Infrastructure Map

Putting it all together, I could reconstruct the complete infrastructure:

  • Event-streaming infrastructure - used for internal application and operational data flows
  • Time-series monitoring - metrics collection and analysis
  • Centralized logging - aggregation and search of system and application logs
  • Object storage - internal storage and backup workloads
  • Container orchestration - management of containerized workloads
  • Relational databases - application and operational data storage
  • Remote connectivity infrastructure - connectivity between managed sites and services

The monitored organizations varied in size and infrastructure. Each had dedicated monitoring groups containing servers, network devices, and site-specific assets.

#Why This Chain Matters

This isn't just "found an old Grafana, read some files." The chain is:

  1. Old, unpatched software (Grafana 8.0.0 in 2026) →
  2. CVE with public exploit (CVE-2021-43798, three years old) →
  3. Credential misconfiguration (password in json_data not secure_json_data) →
  4. API access escalation (Grafana reader → Zabbix API user) →
  5. Complete infrastructure enumeration (Including hosts, network, and access details)

Each link in the chain was individually low-effort. But together, they scaled from a file read bug to a full enterprise infrastructure compromise.

#The Remediation

The fixes are straightforward on paper:

  1. Patch Grafana. 8.3.0 fixed this in 2021. There is no excuse for 8.0.0 in 2026.
  2. Rotate everything. Every credential in that database is compromised. Zabbix password, SNMP community, webhook URLs, every datasource password.
  3. Don't expose admin interfaces. Grafana and Zabbix should never be internet-facing without a VPN or identity-aware proxy.
  4. Use secure_json_data. Grafana has two fields for datasource config: json_data (plaintext) and secure_json_data (encrypted). Use the right one.
  5. Monitor access to grafana.db. If someone reads your Grafana database, you should know.

#The Graph

Here's what the chain looks like in a single diagram:

curl --path-as-is
→ /etc/passwd (Alpine, containerized)
→ grafana.ini (config, secret_key)
→ grafana.db (several megabytes SQLite)
→ Zabbix API password (plaintext)
→ Teams webhook URL
→ 17 user emails + names
→ MS SQL creds (AES-encrypted, key in grafana.ini)
→ Internal network topology
→ Zabbix API auth
→ Multiple hosts enumerated
→ Extensive host-group structure identified
→ Multiple organizations and environments mapped
→ SNMP community: REDACTEDever!
→ Numerous automation scripts identified
→ Complete infrastructure blueprint

All from a single curl command against a three year old vulnerability.

#The Takeaway

Old vulnerabilities on internal tools don't stay internal. Monitoring platforms like Grafana and Zabbix sit at the intersection of everything - they connect to every datasource, track every server, notify every team. A single blind spot in their security posture cascades across the entire infrastructure.

If you're running Grafana, check your version. If it's below 8.3.0, assume compromise. Audit your datasource configurations - are credentials in json_data or secure_json_data? Check your Zabbix API users - are they read-only in name but read-everything in practice?

And for the love of everything holy, don't put monitoring dashboards on the public internet.

This post is based on a real security assessment conducted in July 2026. All company names, personal identifiers, precise environmental figures, and specific credentials have been generalized or redacted. The technical details are presented as an accurate representation of the exploitation chain while intentionally omitting identifying characteristics.

Pass it on

Never miss an issue

New stories land in the feed as they're published.

rss.xml

More fables