Centrifugo: Client-forgeable headers emulation lets any client spoof headers forwarded to proxy backends
Collected exploitation and prediction evidence
Risk source coverageCISA KEV is observed exploitation evidence. FIRST EPSS is a dated prediction of exploitation in the next 30 days. Missing scores are unknown. This collector requests predictions only for explicit CVE aliases in the public NuGet archive; Microsoft release views retain their existing prediction scope.
No collected risk observation for these identifiers. This does not establish absence of exploitation or a zero probability.
cve-program · CVE-2026-71485
PublishedCentrifugo 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.
- Source published
- 20 Aug 2026 21:01:00 UTC
- Source modified
- 25 Aug 2026 15:23:47 UTC
- Observed here
- 23 Oct 2026 15:48:27 UTC
- Source terms
- CVE Program Terms of Use
Original source record · Cite this exact observation · Complete original publisher JSON
This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: cve-program · CVE Program Terms of Use. Source text is retained; field grouping and change labels are provided by ChangeIntel.
CVSS 3.1 · 9.1 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
euvd · EUVD-2026-63649
PublishedCentrifugo 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.
EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON.
Original publisher date fields
datePublished: Aug 20, 2026, 9:01:00 PM
dateUpdated: Aug 25, 2026, 3:23:47 PM
- Source published
- Aug 20, 2026, 9:01:00 PM (timezone not stated)
- Source modified
- Aug 25, 2026, 3:23:47 PM (timezone not stated)
- Observed here
- 7 Nov 2026 14:23:27 UTC
- Source terms
- ENISA EUVD · source terms and attribution apply
Original source record · Cite this exact observation · Complete original publisher JSON
This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: euvd · ENISA EUVD · source terms and attribution apply. Source text is retained; field grouping and change labels are provided by ChangeIntel.
EUVD CVSS 3.1 · 9.1 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
nvd · CVE-2026-71485
PublishedCentrifugo 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.
NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON.
Source analysis status: Deferred
Weakness classifications: CWE-290
Original publisher date fields
published: 2026-08-20T21:17:08.707
lastModified: 2026-10-18T20:10:00.110
- Source published
- 20 Aug 2026 21:17:08 UTC
- Source modified
- 18 Oct 2026 20:10:00 UTC
- Observed here
- 25 Oct 2026 15:18:57 UTC
- Source terms
- NIST NVD usage terms; underlying source attribution retained
Original source record · Cite this exact observation · Complete original publisher JSON
This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: nvd · NIST NVD usage terms; underlying source attribution retained. Source text is retained; field grouping and change labels are provided by ChangeIntel.
CVSS 3.1 · [email protected] · Secondary · 9.1 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
osv · GHSA-9468-v6mj-fppw
Published## 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 `http_headers` / `grpc_metadata` 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, sub_refresh, map_publish, map_remove, shared_poll_refresh) 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 `http_headers: ["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": "<any value>"}`. 3. Centrifugo forwards `X-Trusted-User: <attacker value>` to the backend exactly as if a trusted intermediary had set it. 4. The backend, trusting this header per its own design, grants whatever access/identity it associates with that value. ### Impact Full spoofing of any header value the backend trusts for authentication/authorization, for every proxy call type, for the lifetime of the connection -- up to full account/identity impersonation depending on backend logic. No credentials, JWT, or API key required. ### Vulnerable Code ```go // internal/proxy/http.go func requestHeaders(ctx context.Context, allowedHeaders, allowedMetaKeys []string, staticHeaders map[string]string) http.Header { headers := http.Header{} for k, v := range staticHeaders { headers.Set(k, v) } emulatedHeaders, _ := clientcontext.GetEmulatedHeadersFromContext(ctx) // 100% client-controlled for k, v := range emulatedHeaders { if slices.Contains(allowedHeaders, strings.ToLower(k)) { headers.Set(k, v) // forwarded to backend as a real outgoing HTTP header } } httpHeaders, hasHTTPHeaders := middleware.GetHeadersFromContext(ctx) // real headers, if present for k, vv := range httpHeaders { if slices.Contains(allowedHeaders, strings.ToLower(k)) { headers[k] = vv // only overrides if SAME header name was ALSO on the real request } } ... } ``` ```go // internal/unigrpc/grpc.go -- never goes through HTTP middleware, no competing real-header check at all connectRequest := &protocol.ConnectRequest{ Token: req.Token, Data: req.Data, Name: req.Name, Version: req.Version, Headers: req.Headers, // the gRPC client's own protobuf field } ``` ### Recommended Fix Document explicitly that `http_headers`/`grpc_metadata` values can also be supplied by the connecting client itself via "headers emulation" and are not guaranteed to come from a trusted reverse proxy. Provide a separate allowlist (e.g. `trusted_http_headers`) populated only from genuine transport-level HTTP headers, never from client-supplied `ConnectRequest.headers`, for operators who need an unforgeable header. For uniGRPC, consider disabling `http_headers` forwarding entirely since there is no transport-level header concept to fall back on. ### Verification Dynamically confirmed against the official `centrifugo/centrifugo:v6.8.3` Docker image on BOTH the bidirectional WebSocket transport and the unidirectional gRPC transport, using a minimal backend that logs every header it receives: - WS: connecting with `{"connect": {"headers": {"x-trusted-user": "admin-impersonation-via-headers-emulation"}}}` resulted in the backend receiving `X-Trusted-User: admin-impersonation-via-headers-emulation`, despite no such header existing on the real WebSocket upgrade HTTP request. - uniGRPC: calling the `Consume` RPC with `ConnectRequest(headers={"x-trusted-user": "admin-impersonation-via-unigrpc"})` (zero real gRPC metadata set) resulted in the backend receiving `X-Trusted-User: admin-impersonation-via-unigrpc`. - Control tests (no `headers` field / no metadata) confirmed the header is absent from the backend's request in the baseline case.
- Source published
- 2 Sep 2026 23:41:37 UTC
- Source modified
- 28 Sep 2026 17:11:21 UTC
- Observed here
- 24 Oct 2026 13:19:41 UTC
- Source terms
- GitHub Advisory Database · CC-BY-4.0
Original source record · Cite this exact observation · Complete original publisher JSON
This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: osv · GitHub Advisory Database · CC-BY-4.0. Source text is retained; field grouping and change labels are provided by ChangeIntel.
CVSS_V3 · CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
Publisher rating · CRITICAL
osv · GO-2026-6490
PublishedCentrifugo: Client-forgeable headers emulation lets any client spoof headers forwarded to proxy backends in github.com/centrifugal/centrifugo
- Source published
- 28 Sep 2026 16:43:40 UTC
- Source modified
- 28 Sep 2026 17:00:16 UTC
- Observed here
- 24 Oct 2026 13:19:41 UTC
- Source terms
- OSV · upstream source license applies
Original source record · Cite this exact observation · Complete original publisher JSON
This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: osv · OSV · upstream source license applies. Source text is retained; field grouping and change labels are provided by ChangeIntel.