Every CVE Search/ Get API key

CVE-2026-71485

Centrifugo: Client-forgeable headers emulation lets any client spoof headers forwarded to proxy backends

9.1 CriticalFix available

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.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
High
Availability
None

Exploit likelihood

0.61%Up 0.2 points since Aug 21, 2026
90%50%10%1%

What each source reports

CVE List Score used 9.1

Centrifugo: Client-forgeable headers emulation lets any client spoof headers forwarded to proxy backends

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.

Record
CVE-2026-71485
CVSS 3.1
9.1 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
Weakness
CWE-290
Updated
2026-11-02
EUVDEUVD-2026-63649 9.1

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.

Record
EUVD-2026-63649
CVSS 3.1
9.1 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-9468-v6mj-fppw 9.1

Centrifugo: Client-forgeable headers emulation lets any client spoof headers forwarded to proxy backends

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

// 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
        }
    }
    ...
}
// 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…

Record
GHSA-9468-v6mj-fppw
CVSS 3.1
9.1 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
Weakness
CWE-290
Updated
2026-11-02
NVD 9.1

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.

Record
CVE-2026-71485
CVSS 3.1
9.1 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
Weakness
CWE-290
Updated
2026-11-02
OSV 9.1

Centrifugo: Client-forgeable headers emulation lets any client spoof headers forwarded to proxy backends

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.

Record
CVE-2026-71485
CVSS 3.1
9.1 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
Weakness
CWE-290
Updated
2026-11-02
OSVGHSA-9468-v6mj-fppw 9.1

Centrifugo: Client-forgeable headers emulation lets any client spoof headers forwarded to proxy backends

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

// 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
        }
    }
    ...
}
// 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…

Record
GHSA-9468-v6mj-fppw
CVSS 3.1
9.1 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
Weakness
CWE-290
Updated
2026-11-02
OSVGO-2026-6490 No score

Centrifugo: Client-forgeable headers emulation lets any client spoof headers forwarded to proxy backends in github.com/centrifugal/centrifugo

Centrifugo: Client-forgeable headers emulation lets any client spoof headers forwarded to proxy backends in github.com/centrifugal/centrifugo

Record
GO-2026-6490
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
github.com/centrifugal/centrifugo
Go
through 6.8.4
6.9.0
github.com/centrifugal/centrifugo
Go
before 6.9.0
6.9.0
github.com/centrifugal/centrifugo
Go
All versions None known
github.com/centrifugal/centrifugo/v3
Go
All versions None known
github.com/centrifugal/centrifugo/v4
Go
All versions None known
github.com/centrifugal/centrifugo/v5
Go
All versions None known
github.com/centrifugal/centrifugo/v6
Go
before 6.9.0
6.9.0

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-71485 is a critical vulnerability (CVSS 9.1) in Centrifugal Centrifugo, published August 20, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.61%, the 49th percentile. Fixed in github.com/centrifugal/centrifugo 6.9.0.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open