CVE-2021-39226 Overview
CVE-2021-39226 is an authentication bypass vulnerability in Grafana, an open source data visualization platform. In affected versions, both unauthenticated and authenticated users can view dashboard snapshots with the lowest database key by accessing specific literal paths: /dashboard/snapshot/:key or /api/snapshots/:key. When the public_mode configuration setting is enabled, unauthenticated users can also delete snapshots. This vulnerability enables attackers to enumerate and exfiltrate all snapshot data while simultaneously causing complete data loss through sequential deletion.
Critical Impact
This vulnerability is listed in CISA's Known Exploited Vulnerabilities (KEV) catalog, indicating active exploitation in the wild. Attackers can systematically walk through all snapshot data, exposing sensitive dashboard information and causing irreversible data loss.
Affected Products
- Grafana versions prior to 7.5.11
- Grafana versions 8.x prior to 8.1.6
- Fedora 34 and 35 (grafana package)
Discovery Timeline
- 2021-10-05 - CVE-2021-39226 published to NVD
- 2025-10-24 - Last updated in NVD database
Technical Details for CVE-2021-39226
Vulnerability Analysis
This vulnerability stems from improper access control (CWE-862) and authentication bypass (CWE-287) in Grafana's snapshot handling functionality. The core issue lies in how Grafana's macaron router handles static path matching for snapshot-related endpoints.
The vulnerability allows complete enumeration of snapshot data because the affected endpoints accept literal :key strings instead of properly validating route parameters. When a request is made to /api/snapshots/:key with the literal string :key, the router's fast-match logic for static routes incorrectly matches this path, returning the snapshot with the lowest database key rather than requiring a valid snapshot key.
This creates two attack scenarios: First, iterative viewing allows attackers to access each snapshot sequentially by viewing and deleting snapshots one by one. Second, when public_mode is enabled, even unauthenticated attackers can perform this enumeration, significantly expanding the attack surface.
Root Cause
The root cause is a static path matching issue in Grafana's embedded macaron router. The router's ServeHTTP function performs a fast-match optimization for static routes before checking for dynamic path parameters. When the URL path contains literal colon (:) or asterisk (*) characters, the router should skip static matching and proceed to dynamic route matching. However, the vulnerable code path allowed requests with literal :key in the URL to match static routes, bypassing the intended parameter validation.
Additionally, the GetDashboardSnapshot handler did not validate that the key parameter was actually populated, allowing requests with empty or malformed keys to proceed.
Attack Vector
The attack is network-based and requires no authentication in default configurations for viewing snapshots, or when public_mode is enabled for deletion. An attacker can:
- Access /api/snapshots/:key to retrieve the snapshot with the lowest database key
- Delete that snapshot via /api/snapshots-delete/:deleteKey (if authenticated or if public_mode=true)
- Repeat to enumerate through all snapshots in the database
// Security patch in pkg/api/dashboard_snapshot.go - Fix static path matching issue in macaron
// Source: https://github.com/grafana/grafana/commit/2d456a6375855364d098ede379438bf7f0667269
// GET /api/snapshots/:key
func GetDashboardSnapshot(c *models.ReqContext) response.Response {
key := c.Params(":key")
+ if len(key) == 0 {
+ return response.Error(404, "Snapshot not found", nil)
+ }
query := &models.GetDashboardSnapshotQuery{Key: key}
err := bus.Dispatch(query)
// Security patch in pkg/macaron/router.go - Fix static path matching issue in macaron
// Source: https://github.com/grafana/grafana/commit/2d456a6375855364d098ede379438bf7f0667269
func (r *Router) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if t, ok := r.routers[req.Method]; ok {
// Fast match for static routes
- leaf := r.getLeaf(req.Method, req.URL.Path)
- if leaf != nil {
- leaf.handle(rw, req, nil)
- return
+ if !strings.ContainsAny(req.URL.Path, ":*") {
+ leaf := r.getLeaf(req.Method, req.URL.Path)
+ if leaf != nil {
+ leaf.handle(rw, req, nil)
+ return
+ }
}
h, p, ok := t.Match(req.URL.EscapedPath())
Detection Methods for CVE-2021-39226
Indicators of Compromise
- HTTP requests to /api/snapshots/:key or /dashboard/snapshot/:key containing literal colon characters
- Sequential requests to snapshot deletion endpoints /api/snapshots-delete/:deleteKey
- Unusual patterns of snapshot access followed by deletion from the same source
- Web server logs showing 200 responses to malformed snapshot key requests
Detection Strategies
- Monitor web access logs for requests containing literal :key or :deleteKey strings in snapshot-related URLs
- Implement alerting on rapid sequential access to snapshot endpoints from single IP addresses
- Review Grafana audit logs for unexpected snapshot deletions or access patterns
- Deploy web application firewall (WAF) rules to block requests with literal route parameter syntax
Monitoring Recommendations
- Enable detailed access logging on Grafana instances and forward to SIEM
- Create alerts for any requests matching /api/snapshots/:key or /api/snapshots-delete/:deleteKey patterns
- Monitor for sudden decreases in snapshot counts which may indicate exploitation
- Track authentication failures and unusual access patterns to dashboard snapshot endpoints
How to Mitigate CVE-2021-39226
Immediate Actions Required
- Upgrade Grafana to version 8.1.6 or later for 8.x installations
- Upgrade Grafana to version 7.5.11 or later for 7.x installations
- If immediate upgrade is not possible, implement reverse proxy rules to block affected paths
- Review snapshot access logs for signs of prior exploitation
- Audit existing snapshots and restore from backup if data loss is suspected
Patch Information
Grafana has released security patches in versions 8.1.6 and 7.5.11. The fix addresses both the router-level static path matching issue and adds validation in the snapshot handler to reject empty key parameters. For detailed information, see the Grafana Release Notes for 7.5.11 and Grafana Release Notes for 8.1.6. The security advisory is available at GitHub Grafana Security Advisory GHSA-69j6-29vr-p3j9.
Workarounds
- Use a reverse proxy (nginx, Apache, HAProxy) to block access to vulnerable paths
- The affected literal paths have no normal function and can be safely blocked without side effects
- Disable public_mode configuration to require authentication for snapshot deletion
- Consider temporarily disabling snapshot functionality entirely if patches cannot be applied
# Nginx configuration to block vulnerable paths
location ~ ^/api/snapshots/:key$ {
deny all;
return 404;
}
location ~ ^/api/snapshots-delete/:deleteKey$ {
deny all;
return 404;
}
location ~ ^/dashboard/snapshot/:key$ {
deny all;
return 404;
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

