Security Digest · Vulnerability record
CVE-2026-71485: Centrifugo: Client-forgeable headers emulation lets any client spoof headers forwarded to proxy backends
Centrifugo is an open-source scalable real-time messaging server.
CVSS 9.1 Critical EPSS 0.6% · p48
Should you act?
Critical and remotely reachable
No known exploitation yet, but it is network-reachable without credentials. This signal is computed from CISA KEV, EPSS and CVSS data; it is not an editorial verdict.
- No confirmed exploitation. It is not in CISA’s KEV catalog and CISA’s SSVC assessment records no known exploitation. That can change quickly after a public write-up; re-check if you are affected.
- EPSS 0.6%, percentile 48: FIRST’s model estimates a 0.6% chance of exploitation activity in the next 30 days, higher than 48% of all scored CVEs (low). EPSS is a probability, not a verdict.
- Remotely reachable with no login and no user interaction. If the vulnerable service is exposed to the internet, prioritize it.
- Only applies if your dependency tree includes
github.com/centrifugal/centrifugo(Go) <= 6.8.4, fixed in 6.9.0. Check your lockfile, including transitive dependencies.
What it is
Centrifugo is an open-source scalable real-time messaging server. Prior to 6.9.0, Centrifugo copies the client-controlled protocol.ConnectRequest.headers map through OnClientConnecting in internal/client/handler.go, ConnectEvent.Headers, and SetEmulatedHeadersToContext. The requestHeaders path in internal/proxy/http.go, the requestMetadata path in internal/proxy/grpc.go, and the Consume path in internal/unigrpc/grpc.go can forward an allowlisted value as a trusted backend header or metadata value. A remote client can spoof a header such as x-trusted-user for connect, refresh, subscribe, publish, RPC, and related proxy calls when the backend relies on that header for authentication or authorization. The unidirectional gRPC transport has no transport-level HTTP header that can override the emulated value. This issue is fixed in version 6.9.0.
From the GitHub advisory
Vulnerability Details
File: internal/client/handler.go (OnClientConnecting), internal/proxy/http.go (requestHeaders), internal/proxy/grpc.go (requestMetadata), internal/unigrpc/grpc.go (Consume) Line: handler.go:389,548-552 (e.Headers -> SetEmulatedHeadersToContext), http.go:131-165 (requestHeaders), grpc.go:82-114 (requestMetadata), unigrpc/grpc.go:46 (Headers: req.Headers)
Root Cause The httpheaders / grpcmetadata proxy config options are documented as "List of incoming HTTP header names to forward to the proxy backend" / "List of incoming gRPC metadata keys to forward to the proxy backend" -- implying the value originates from the underlying transport connection (e.g. set by a trusted reverse proxy/API gateway in front of Centrifugo). Operators commonly use this to forward identity/trust headers to their own backend for access-control decisions.
However, the wire protocol used by every Centrifugo transport (protocol.ConnectRequest, field headers) includes a headers map populated entirely from the connecting client's own message (its JSON connect command, or for gRPC, its ConnectRequest protobuf field) -- not from real transport-level HTTP headers. Centrifugo copies this client-supplied map verbatim into ConnectEvent.Headers, then into an "emulated headers" context value used by every proxy type (connect, refresh, subscribe, publish, rpc, subrefresh, mappublish, mapremove, sharedpollrefresh) for the entire connection lifetime. Any header name in the operator's allowlist is forwarded to the backend with the client's own chosen value, unless a header of the exact same name also happens to be present on the genuine underlying HTTP request. For the unidirectional gRPC transport specifically there is no HTTP request at all, so there is no possible override -- the client-controlled value always wins.
Attack Scenario 1. Operator configures a connect proxy with httpheaders: ["x-trusted-user"] (or any header name their backend uses for caller identity/trust). 2. Attacker connects directly to Centrifugo and sends a connect command containing "headers": {"x-trusted-user": " "}. 3. Centrifugo forwards X-Trusted-User: to the backend exactly as if a trusted intermediary had set it. 4. The backend, trusting this header per its own design, grants whatever…
Weakness type: CWE-290.
Product: github.com/centrifugal/centrifugo (Go) · Assigned by: GitHub_M · Published: 2026-08-20
Affected and fixed versions
| Ecosystem | Package | Vulnerable | First fixed |
|---|---|---|---|
| Go | github.com/centrifugal/centrifugo | <= 6.8.4 | 6.9.0 |
| Vendor | Product | Affected versions (per CVE record) |
|---|---|---|
| centrifugal | centrifugo | < 6.9.0 |
Severity scores
| Scored by | CVSS | Score | Vector |
|---|---|---|---|
| GitHub_M | 3.1 | 9.1 Critical | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N |
| GitHub | 3.1 | 9.1 | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N |
- Attack vector: network (remotely reachable)
- Attack complexity: low
- Privileges required: none (no login)
- User interaction: none
- Scope: unchanged
CVSS measures how bad a flaw is if exploited, not how likely exploitation is. Read it next to the exploitation data below.
Exploitation and urgency
- CISA KEV: not listed (no confirmed in-the-wild exploitation known to CISA).
- CISA SSVC assessment: exploitation none, automatable yes, technical impact total.
- FIRST EPSS (model of 2026-10-21): 0.61% probability of exploitation activity in the next 30 days; percentile 48.
Timeline
- — CVE record published by GitHub_M
- — CVE record last updated
- — GitHub-reviewed advisory GHSA-9468-v6mj-fppw published (critical)
Sources and references
Original sources first. Version and fix details should always be confirmed against the vendor or project advisory.
Vulnerability records
- GitHub Advisory GHSA-9468-v6mj-fppw github.com
- CVE.org record CVE-2026-71485 cve.org
- NVD entry CVE-2026-71485 nvd.nist.gov
Other references from the CVE record and advisory
- github.com github.com
- github.com github.com
- github.com github.com
- github.com github.com