go-chi/chi RealIP Middleware IP Spoofing via X-Forwarded-For
The chi RealIP middleware blindly trusts the leftmost value in the X-Forwarded-For header, letting any client forge their source IP and bypass access controls or corrupt audit logs.

The problem
The middleware.RealIP() function in go-chi/chi splits the X-Forwarded-For header on commas and unconditionally promotes the first (leftmost) entry into r.RemoteAddr.
Because a client controls everything to the left of what the immediate proxy appends, any caller can inject an arbitrary IP into that first position. Downstream code reading r.RemoteAddr for rate-limiting, geo-blocking, or audit logging will silently operate on the attacker-supplied value.
Proof of concept
A working proof-of-concept for this issue in github.com/go-chi/chi/middleware, with the exact payload below.
# 1. Start a chi server using middleware.RealIP (see advisory PoC)
# 2. Send a request with a forged leftmost XFF entry:
curl http://localhost:8080 -H 'X-Forwarded-For: 192.0.2.2, 192.0.2.1'
# Server responds:
# remote addr: 192.0.2.2 (want 192.0.2.1)
#
# 192.0.2.2 is the attacker-forged IP.
# 192.0.2.1 is the real client IP appended by the proxy.
# RealIP picks index 0 (leftmost), so the forged IP wins.CWE-346 (Origin Validation Error). The root cause is a hard-coded left-to-right read of XFF with no concept of which proxies are trusted. A legitimate proxy appends the connecting IP to the *right* of the existing header value, so the leftmost entry is always under client control and must never be trusted without validating all entries to its right against a known-good proxy list.
The fix in v5.3.0 (PR #967) deprecated RealIP entirely because its two design choices, mutating r.RemoteAddr and applying a one-size-fits-all header priority list, are unfixable without a breaking API change. The replacement ClientIP family requires the operator to declare exactly which trust source to use (ClientIPFromHeader, ClientIPFromXFF with explicit CIDRs, ClientIPFromXFFTrustedProxies, or ClientIPFromRemoteAddr), and the XFF variant walks right-to-left, skipping trusted entries, to find the first untrusted IP.
The fix
Upgrade to go-chi/chi/v5 >= v5.3.0 and replace middleware.RealIP with exactly one of the new ClientIPFrom* middlewares suited to your infrastructure. Read the resolved IP with middleware.GetClientIP(r) instead of r.RemoteAddr. The old RealIP function is still present but marked deprecated and remains unsafe.
Reported by convto.
Related research
- highchi RealIP Middleware IP Spoofing via Unvalidated X-Forwarded-For Header
- high · 7.7CVE-2026-54910CVE-2026-54910: FileBrowser Quantum Path Traversal in Subtitle Handler
- critical · 9.6CVE-2026-54725CVE-2026-54725: vault-secrets-webhook Annotation SSRF and ServiceAccount Token Theft
- critical · 9.9CVE-2026-54680CVE-2026-54680: kube-logging/logging-operator Fluentd Configuration Injection RCE