Skip to content

Commit 516bfc6

Browse files
committed
docs: [#434] correct CVE-2026-34986 exploitability based on live test
1 parent 8d54e6b commit 516bfc6

1 file changed

Lines changed: 49 additions & 24 deletions

File tree

docs/issues/434-grafana-cves.md

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -84,16 +84,35 @@ algorithm (e.g. `A128KW`) but with an empty `encrypted_key`, go-jose panics tryi
8484
allocate a zero-length slice in `cipher.KeyUnwrap()`. The panic crashes the goroutine
8585
and can bring down the Grafana process entirely.
8686

87-
**Is it exploitable via the public dashboard?** Yes. Grafana parses bearer tokens on
88-
all HTTP requests before checking authentication. An attacker can send:
87+
**Is it exploitable via the public dashboard?** Not via the simple bearer-token path
88+
tested on 2026-04-14. Testing against the live `grafana.torrust-tracker-demo.com`
89+
(`12.4.2`) confirmed the attack does **not** trigger a panic from a plain
90+
`Authorization: Bearer <JWE>` header:
91+
92+
```console
93+
$ TOKEN="eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..AAAA.AAAA.AAAA"
94+
$ curl -si -H "Authorization: Bearer $TOKEN" https://grafana.torrust-tracker-demo.com/api/org
95+
HTTP/2 401 {"message":"Invalid API key"}
96+
```
97+
98+
Grafana's auth middleware routed the token to the **API key** handler
99+
(`auth.client.api-key`), which performs a simple database lookup — it never calls
100+
go-jose to parse the token. Server log:
89101

90102
```text
91-
Authorization: Bearer <crafted-JWE-with-empty-encrypted_key>
103+
INFO Failed to authenticate request client=auth.client.api-key error="[api-key.invalid] API key is invalid"
92104
```
93105

94-
to any endpoint on `grafana.torrust-tracker-demo.com` without any credentials and
95-
crash Grafana. The CVSS confirms this: no privileges required, no user interaction,
96-
network-reachable.
106+
The go-jose panic is only reachable when Grafana calls `jwe.ParseEncrypted()` on
107+
user input — which happens in specific auth flows (e.g. service-account JWT auth,
108+
certain OIDC callback paths) but **not** via the default API-key/bearer-token
109+
routing used here.
110+
111+
**Revised risk**: The CVSS `AV:N/AC:L/PR:N` reflects the library's theoretical
112+
attack surface. In practice, this deployment is not vulnerable to the simple
113+
bearertoken attack vector. The CVE is real in the binary and the upgrade to 13.0.0
114+
is still correct (defence in depth), but the immediate risk of remote DoS on
115+
`grafana.torrust-tracker-demo.com` via this technique is not confirmed.
97116

98117
**Grafana's fix**: merged in PR
99118
[grafana/grafana#121830](https://github.com/grafana/grafana/pull/121830) 2 weeks
@@ -106,9 +125,13 @@ labelled `no-backport` — **no fix will be released for any 12.x version**.
106125

107126
#### Proof-of-concept
108127

109-
> ⚠️ **Run against a local instance first.** Sending this to the live demo will
110-
> crash the public Grafana at `grafana.torrust-tracker-demo.com` until Docker
111-
> restarts it.
128+
> ⚠️ **Run against a local instance first.**
129+
>
130+
> **Update (2026-04-14)**: The attack was tested against the live demo
131+
> (`grafana.torrust-tracker-demo.com`, `12.4.2`) and did **not** produce a panic.
132+
> Grafana routed the JWE bearer token to the API key handler rather than the
133+
> JWE parser. The PoC below may only work in configurations where JWT auth is
134+
> explicitly enabled or via specific OIDC flows.
112135
113136
##### Step 1 — Generate the crafted JWE token
114137

@@ -288,18 +311,20 @@ internal-only code paths, not reachable via Grafana's HTTP layer.
288311
All remaining CVEs (10 HIGH, 0 CRITICAL in `grafana/grafana:13.0.0`) require local
289312
access or are not reachable via Grafana's HTTP layer:
290313

291-
| CVE | Exploitable remotely? | Reason |
292-
| -------------- | --------------------- | -------------------------------------------------------------------------- |
293-
| CVE-2026-28390 | No | Caddy terminates TLS; Grafana never processes raw TLS |
294-
| CVE-2026-22184 | No | `untgz` path — unreachable via dashboard UI |
295-
| CVE-2026-34040 | No | Moby Docker-client code, not a Grafana HTTP endpoint |
296-
| CVE-2026-39883 | No | Local PATH-hijack — requires host shell access |
297-
| CVE-2026-25679 | No | `elasticsearch` plugin internal path — not reachable via dashboard |
298-
| CVE-2026-27137 | No | `elasticsearch` plugin internal path — not reachable via dashboard |
299-
| CVE-2026-32280 | No | Go chain-building DoS on outbound TLS — not reachable from public internet |
300-
| CVE-2026-32282 | No | Local `Root.Chmod` symlink — requires host shell access |
301-
302-
**Overall risk**: CVE-2026-34986 (unauthenticated remote DoS) is eliminated by
303-
upgrading to `grafana/grafana:13.0.0`. The 10 remaining HIGH CVEs have no realistic
304-
remote attack path in this deployment. No CRITICALs in any version we are now
305-
deploying.
314+
| CVE | Exploitable remotely? | Reason |
315+
| -------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
316+
| CVE-2026-28390 | No | Caddy terminates TLS; Grafana never processes raw TLS |
317+
| CVE-2026-22184 | No | `untgz` path — unreachable via dashboard UI |
318+
| CVE-2026-34040 | No | Moby Docker-client code, not a Grafana HTTP endpoint |
319+
| CVE-2026-39883 | No | Local PATH-hijack — requires host shell access |
320+
| CVE-2026-25679 | No | `elasticsearch` plugin internal path — not reachable via dashboard |
321+
| CVE-2026-27137 | No | `elasticsearch` plugin internal path — not reachable via dashboard |
322+
| CVE-2026-32280 | No | Go chain-building DoS on outbound TLS — not reachable from public internet |
323+
| CVE-2026-32282 | No | Local `Root.Chmod` symlink — requires host shell access |
324+
| CVE-2026-34986 | Not confirmed | JWE bearer token routed to API-key handler in live test; panic requires a code path that calls `jwe.ParseEncrypted()` (e.g. JWT-auth or OIDC flows) |
325+
326+
**Overall risk**: CVE-2026-34986 was not confirmed exploitable via simple bearer token
327+
on this deployment — the API-key auth handler intercepted the request before go-jose
328+
was called. The upgrade to `grafana/grafana:13.0.0` eliminates the vulnerability at
329+
its root regardless. The remaining 10 HIGH CVEs have no realistic remote attack path
330+
in this deployment. No CRITICALs in any version we are now deploying.

0 commit comments

Comments
 (0)