chi RealIP Middleware IP Spoofing via Unvalidated X-Forwarded-For Header
chi's built-in RealIP middleware blindly trusts client-supplied headers like X-Forwarded-For and X-Real-IP without verifying the request came from a trusted proxy, letting any attacker fake their IP…

The problem
The middleware.RealIP function in go-chi/chi reads True-Client-IP, X-Real-IP, and X-Forwarded-For headers in that order and unconditionally overwrites r.RemoteAddr with whatever value the client supplied. No check is made to confirm the request actually arrived from a known, trusted proxy.
Any attacker who can reach the chi server directly, or whose upstream proxy does not sanitize those headers, can set an arbitrary IP. This breaks IP-based access controls, rate limiting, geo-fencing, and produces falsified audit logs.
Proof of concept
A working proof-of-concept for this issue in github.com/go-chi/chi/middleware, with the exact payload below.
curl -H "X-Forwarded-For: 127.0.0.1" http://target:8080/adminThe old realIP() function called r.Header.Get(xForwardedFor) and took the leftmost comma-separated value, then assigned it directly to r.RemoteAddr. HTTP headers are fully attacker-controlled, so the leftmost XFF entry is always the one the client wrote.
The patch (v5.3.0, PR #967) removes RealIP as a safe default and replaces it with four new middlewares (ClientIPFromHeader, ClientIPFromXFF, ClientIPFromXFFTrustedProxies, ClientIPFromRemoteAddr) that require the operator to explicitly declare trusted proxy CIDRs or a trusted header name. ClientIPFromXFF walks the XFF chain right-to-left, stopping at the first IP not covered by a declared trusted CIDR, so attacker-appended leftmost entries are never reached.
The result is stored in request context via GetClientIP/GetClientIPAddr and r.RemoteAddr is never mutated.
The fix
Upgrade to go-chi/chi v5.3.0 or later. Replace middleware.RealIP with exactly one of the new ClientIPFrom* middlewares that matches your deployment topology. For a server behind Cloudflare use middleware.ClientIPFromHeader("CF-Connecting-IP"); for a proxy fleet with known CIDRs use middleware.ClientIPFromXFF("<cidr>", ...).
For direct internet exposure with no proxy use middleware.ClientIPFromRemoteAddr. Read the resolved IP with middleware.GetClientIP(ctx) instead of r.RemoteAddr.
Reported by rezmoss.
Related research
- highgo-chi/chi RealIP Middleware IP Spoofing via X-Forwarded-For
- critical · 9.1CVE-2026-54089CVE-2026-54089: File Browser Authentication Bypass via Proxy Header Forgery
- 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