← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
CVE-2026-21720 · CWE-400 · Disclosed 2026-01-27

Every uncached /avatar/:hash request spawns a goroutine that refreshes the Gravatar image

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is a lobby doorbell that can be jammed until the receptionist quits answering

CVE-2026-21720 is an unauthenticated denial-of-service bug in Grafana’s avatar handling. On vulnerable builds, every uncached GET /avatar/:hash request kicks off a Gravatar refresh goroutine; when that refresh sits in the 10-slot worker queue for more than three seconds, the request handler times out, stops listening, and the goroutine can block forever trying to send on an unbuffered channel. Vendor-listed affected ranges are >=3.0.0 <11.6.9+security-01, >=12.0.0 <12.0.8+security-01, >=12.1.0 <12.1.5+security-01, >=12.2.0 <12.2.3+security-01, and 12.3.0.

The vendor’s 7.5/HIGH score is technically defensible in a vacuum because the bug is remote, unauthenticated, and availability-impacting. In real enterprise operations, though, this is still *only* a Grafana process crash path, it needs sustained cache-miss traffic rather than a single packet win, and the most exposed population is the subset of Grafana instances reachable to attackers at all. That combination pushes it down a bucket for most fleets.

"Pre-auth and easy to hit, but this is a service-crash bug with no exploitation signal and a narrower real blast radius than CVSS implies."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Reach the avatar endpoint

An attacker sends unauthenticated HTTP requests to Grafana’s /avatar/:hash endpoint using a trivial client such as curl or a load tool like wrk. No login or user interaction is required if the Grafana web interface is reachable from the attacker’s network position.
Conditions required:
  • A vulnerable Grafana instance is reachable over HTTP/HTTPS
  • The attacker can send requests to the web UI path space
Where this breaks in practice:
  • Many enterprise Grafana deployments are internal-only, behind VPN, SSO, reverse proxy ACLs, or zero-trust access
  • Some teams do not expose Grafana directly to the public Internet
Detection/coverage: Low-friction to observe in reverse-proxy and Grafana access logs because the URI pattern is stable (/avatar/). External attack-surface scanners can identify Grafana exposure, but not whether the endpoint is being abused.
STEP 02

Force repeated cache misses

The attacker rotates random avatar hashes with a tool such as hey or ab so requests stay uncached and each one triggers a Gravatar refresh path. The bug is not about normal avatar fetch volume; it is about intentionally manufacturing endless cache misses.
Conditions required:
  • Randomized hash values to avoid cache hits
  • Enough request volume to keep the refresh path busy
Where this breaks in practice:
  • HTTP rate limits, CDN caching, or reverse-proxy throttling can materially reduce effective miss volume
  • If Gravatar use is disabled in configuration, this path may not be reachable in practice
Detection/coverage: Look for a spike in unique /avatar/<hash> requests, especially high-cardinality random hashes. WAF/CDN telemetry is often better than host telemetry for spotting this stage.
STEP 03

Saturate the refresh queue and leak goroutines

Once the 10-slot worker queue backs up past three seconds, the waiting handler times out while the spawned goroutine can remain blocked trying to send its result. With sustained abuse, goroutine count grows roughly linearly and memory pressure accumulates until the process degrades or dies.
Conditions required:
  • Queue saturation long enough to exceed the three-second timeout
  • Sustained request stream rather than a one-off probe
Where this breaks in practice:
  • The attacker must keep pressure on the service; this is not a one-request crash
  • Host resource limits, autoscaling, or upstream connection failures can slow time-to-impact
Detection/coverage: Best host-side indicators are go_goroutines, RSS growth, OOM events, elevated latency, and pprof output if profiling is enabled. Traditional vuln scanners do not validate this runtime condition.
STEP 04

Crash or degrade Grafana

Eventually the Grafana process exhausts memory or becomes unstable enough that dashboards and API requests fail. Practical attacker tooling is still basic HTTP flood generation, not a specialized exploit chain.
Conditions required:
  • The instance is important enough that Grafana availability matters
  • Traffic volume persists long enough to exhaust process resources
Where this breaks in practice:
  • Blast radius is usually limited to Grafana availability, not the monitored systems themselves
  • Process supervision may restart the service, reducing dwell time unless the attack continues
Detection/coverage: Existing uptime monitoring, systemd/service restarts, OOM killer logs, container restart counts, and dashboard health probes usually catch the impact quickly.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo authoritative evidence of active exploitation surfaced in the reviewed sources. It is not present in CISA KEV based on the catalog reviewed.
Proof-of-concept availabilityNo named public exploit repository stood out in the reviewed sources; this looks like a *trivial-to-recreate* HTTP abuse pattern rather than a polished exploit kit.
EPSS0.00036 per the user-supplied intel, which is very low and aligns with weak exploitation demand.
KEV statusNot KEV-listed as of the reviewed CISA catalog page; no KEV due date pressure applies.
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H — this correctly captures easy remote reachability, but it overstates operational urgency by ignoring exposure narrowing and the availability-only blast radius.
Affected versionsVendor advisory lists >=3.0.0 <11.6.9+security-01, >=12.0.0 <12.0.8+security-01, >=12.1.0 <12.1.5+security-01, >=12.2.0 <12.2.3+security-01, and 12.3.0.
Fixed versionsVendor fixed builds are 11.6.9+security-01, 12.0.8+security-01, 12.1.5+security-01, 12.2.3+security-01, and 12.3.1+security-01; Grafana’s upgrade guidance notes later patch releases in a branch also carry those security fixes.
Scanning and exposureInternet exposure of Grafana is common enough that platforms like Shodan and Censys routinely track it, but no reviewed source provided trustworthy CVE-specific attack telemetry or a current exposed-host count. Inference: this matters mainly for externally reachable Grafana, not the average internal-only deployment.
DisclosurePublished 2026-01-27 by Grafana Labs; NVD later added affected CPEs on 2026-02-17.
Reporter and scanner coverageReported by sam18191 via Grafana’s bug bounty program. Nessus has version-based coverage via plugin 297198, which helps inventory vulnerable builds but does not prove runtime exploitability.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to MEDIUM (6.3/10)

The decisive downgrade factor is that this is an availability-only bug that usually requires the attacker to have direct reachability to Grafana and to sustain enough cache-miss traffic to keep the queue timing out. That is materially weaker than an internet-wide one-shot RCE or auth bypass, even though the raw CVSS math says 'unauthenticated remote.'

HIGH Affected/fixed version mapping from Grafana advisory and NVD
MEDIUM Real-world exposure reduction from internal-only or access-controlled Grafana deployments
MEDIUM Absence of public exploitation evidence at time of review

Why this verdict

  • Start from 7.5/HIGH: vendor scoring is reasonable because the bug is remote, unauthenticated, and can crash the service.
  • Downward adjustment for attacker position: the attacker still needs network reachability to the Grafana web app, and a large share of enterprise Grafana is internal-only or gated behind VPN/SSO/reverse proxy policy.
  • Downward adjustment for exploit friction: this is not a one-request kill; the attacker must sustain randomized cache-miss traffic long enough to keep the 10-slot queue timing out and leak goroutines.
  • Downward adjustment for blast radius: impact is usually limited to Grafana service availability, not code execution, data theft, or compromise of monitored assets.
  • No upward pressure from threat intel: no KEV listing, no solid in-the-wild reporting, and a very low EPSS keep this out of the urgent bucket.

Why not higher?

There is no evidence here of code execution, privilege gain, tenant escape, or durable compromise. The chain also assumes direct reachability to Grafana plus sustained traffic pressure, which is a meaningful practical brake compared with truly urgent pre-auth bugs.

Why not lower?

It still deserves attention because the endpoint is unauthenticated and the exploit concept is simple enough for any attacker with HTTP flood capability. If you run Grafana on the public Internet or it backs operational visibility for responders, the availability hit can be painful even without deeper compromise.

05 · Compensating Control

What to do — in priority order.

  1. Restrict Grafana reachability — Put Grafana behind VPN, zero-trust access, IP allowlists, or an authenticated reverse proxy so unauthenticated Internet users cannot hit /avatar/* at all. For a MEDIUM verdict there is no noisgate mitigation SLA, but do this immediately on any Internet-facing instance because it is the cleanest exposure reducer.
  2. Disable Gravatar — Set disable_gravatar = true in grafana.ini to remove the vulnerable avatar refresh path from normal operation. There is no noisgate mitigation SLA for MEDIUM; use this as low-risk containment while you work the patch into the remediation window.
  3. Rate-limit /avatar/ — Apply per-IP and burst limits at the CDN, WAF, ingress controller, or reverse proxy specifically for /avatar/ requests so random-hash floods cannot keep the refresh queue saturated. This is especially useful where Grafana must remain externally reachable.
  4. Alert on goroutine and memory growth — Monitor Grafana process RSS, restart counts, OOM events, and Go runtime metrics like go_goroutines so you detect abuse before the process falls over. This does not fix the bug, but it shortens outage duration and improves confidence that the control path is working.
What doesn't work
  • MFA does not help because the vulnerable path is unauthenticated.
  • Endpoint AV/EDR does not prevent the trigger condition; this is a normal-looking HTTP workload causing application-level resource exhaustion.
  • Generic network IDS signatures are weak here because the requests can look like ordinary GET /avatar/<hash> traffic unless you key on volume and hash cardinality.
06 · Verification

Crowdsourced verification payload.

Run this on the Grafana host with a shell that can execute grafana-server -v, or with access to the local package database. Invoke it as bash check_cve_2026_21720.sh from the server; no root is required unless your package manager metadata is restricted. It performs a version-based check and prints exactly VULNERABLE, PATCHED, or UNKNOWN.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check_cve_2026_21720.sh
# Version-based verification for Grafana CVE-2026-21720
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN

set -u

normalize_version() {
  # Strip leading v and Grafana security suffixes for branch comparisons.
  echo "$1" | sed -E 's/^v//; s/\+security-[0-9]+$//'
}

version_lt() {
  [ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" != "$2" ]
}

version_ge() {
  ! version_lt "$1" "$2"
}

get_version() {
  local v=""

  if command -v grafana-server >/dev/null 2>&1; then
    v=$(grafana-server -v 2>/dev/null | sed -nE 's/.*Version ([^ ]+).*/\1/p' | head -n1)
  fi

  if [ -z "$v" ] && command -v rpm >/dev/null 2>&1; then
    v=$(rpm -q --qf '%{VERSION}\n' grafana 2>/dev/null | head -n1)
    [ -z "$v" ] && v=$(rpm -q --qf '%{VERSION}\n' grafana-enterprise 2>/dev/null | head -n1)
  fi

  if [ -z "$v" ] && command -v dpkg-query >/dev/null 2>&1; then
    v=$(dpkg-query -W -f='${Version}\n' grafana 2>/dev/null | sed 's/-.*//' | head -n1)
    [ -z "$v" ] && v=$(dpkg-query -W -f='${Version}\n' grafana-enterprise 2>/dev/null | sed 's/-.*//' | head -n1)
  fi

  if [ -z "$v" ]; then
    return 1
  fi

  normalize_version "$v"
  return 0
}

is_vulnerable() {
  local v="$1"

  # Affected ranges from advisory, normalized for comparison.
  if version_ge "$v" "3.0.0" && version_lt "$v" "11.6.9"; then return 0; fi
  if version_ge "$v" "12.0.0" && version_lt "$v" "12.0.8"; then return 0; fi
  if version_ge "$v" "12.1.0" && version_lt "$v" "12.1.5"; then return 0; fi
  if version_ge "$v" "12.2.0" && version_lt "$v" "12.2.3"; then return 0; fi
  if [ "$v" = "12.3.0" ]; then return 0; fi

  return 1
}

main() {
  local version=""
  if ! version=$(get_version); then
    echo "UNKNOWN"
    exit 2
  fi

  if is_vulnerable "$version"; then
    echo "VULNERABLE"
    exit 1
  fi

  # Patched branches per Grafana advisory / release model.
  if { version_ge "$version" "11.6.9" && version_lt "$version" "12.0.0"; } || \
     { version_ge "$version" "12.0.8" && version_lt "$version" "12.1.0"; } || \
     { version_ge "$version" "12.1.5" && version_lt "$version" "12.2.0"; } || \
     { version_ge "$version" "12.2.3" && version_lt "$version" "12.3.0"; } || \
     version_ge "$version" "12.3.1"; then
    echo "PATCHED"
    exit 0
  fi

  echo "UNKNOWN"
  exit 2
}

main "$@"
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning, pull a list of all self-managed Grafana instances, separate Internet-reachable from internal-only, and verify versions first. Because this lands at MEDIUM, there is no noisgate mitigation SLA — go straight to the 365-day remediation window for normal internal deployments, but for any public-facing or operations-critical Grafana you should still apply low-cost containment like access restriction, disable_gravatar, or /avatar/ rate limiting immediately while you schedule the vendor fix. Your noisgate remediation SLA is ≤365 days to move vulnerable hosts onto a fixed branch such as 11.6.9+security-01, 12.0.8+security-01, 12.1.5+security-01, 12.2.3+security-01, or 12.3.1+security-01 or later equivalent patch releases.

Sources

  1. Grafana advisory for CVE-2026-21720
  2. Grafana security advisories index
  3. NVD entry for CVE-2026-21720
  4. Grafana configuration docs (`disable_gravatar`)
  5. Grafana upgrade guidance for `+security-01` releases
  6. Tenable Nessus plugin 297198
  7. CISA Known Exploited Vulnerabilities catalog
  8. Grafana 12.3.1 download page
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.