Every CVE Search/ Get API key

CVE-2026-118651

Echo: Reverse Proxy Forwards Attacker-Supplied X-Real-IP to Upstream by Default

5.3 MediumFix available

Echo is a Go web framework. From 4.0.0 until 5.4.0, the Proxy middleware can preserve an attacker-supplied X-Real-IP header and forward it to an upstream service when Echo.IPExtractor is not configured. A remote client can therefore make upstream services receive a spoofed client address, undermining IP-based access controls, rate limiting, audit logging, or geographic restrictions that trust Echo's forwarded identity. This issue is fixed in Echo 5.4.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
None
Integrity
Low
Availability
None

Exploit likelihood

0.21%Unchanged since Oct 29, 2026
90%50%10%1%

What each source reports

CVE List Score used 5.3

Echo: Reverse Proxy Forwards Attacker-Supplied X-Real-IP to Upstream by Default

Echo is a Go web framework. From 4.0.0 until 5.4.0, the Proxy middleware can preserve an attacker-supplied X-Real-IP header and forward it to an upstream service when Echo.IPExtractor is not configured. A remote client can therefore make upstream services receive a spoofed client address, undermining IP-based access controls, rate limiting, audit logging, or geographic restrictions that trust Echo's forwarded identity. This issue is fixed in Echo 5.4.0.

Record
CVE-2026-118651
CVSS 3.1
5.3 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-346
Updated
2026-11-02
EUVDEUVD-2026-112406 5.3

Echo is a Go web framework. From 4.0.0 until 5.4.0, the Proxy middleware can preserve an attacker-supplied X-Real-IP header and forward it to an upstream service when Echo.IPExtractor is not configured. A remote client can therefore make upstream services receive a spoofed client address, undermining IP-based access controls, rate limiting, audit logging, or geographic restrictions that trust Echo's forwarded identity. This issue is fixed in Echo 5.4.0.

Record
EUVD-2026-112406
CVSS 3.1
5.3 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-99jh-6h7p-pp36 5.3

Echo: Reverse Proxy Forwards Attacker-Supplied X-Real-IP to Upstream by Default

Summary

The Echo proxy middleware (middleware/proxy.go) preserves an incoming X-Real-IP header verbatim and forwards it to the upstream service when Echo#IPExtractor is not configured — which is the default. Because any HTTP client can supply an arbitrary X-Real-IP value, an attacker can cause Echo to relay a spoofed client IP address to every upstream service behind the proxy, undermining upstream IP-based access controls, rate limiting, audit logging, and geo-restriction.

Affected Component

  • middleware/proxy.go — ProxyConfig.ToMiddleware(), header-rewriting block (lines 351–355)

Description

The header-preservation condition passes spoofed values to upstream

ProxyConfig.ToMiddleware() (proxy.go:338-405) prepares forwarding headers before dispatching each request. The X-Real-IP rewrite logic at lines 351-355 reads:

// proxy.go:351-355
// Basically it's not good practice to unconditionally pass incoming x-real-ip header to upstream.
// However, for backward compatibility, legacy behavior is preserved unless you configure Echo#IPExtractor.
if req.Header.Get(echo.HeaderXRealIP) == "" || c.Echo().IPExtractor != nil {
    req.Header.Set(echo.HeaderXRealIP, c.RealIP())
}

The condition is TRUE (and therefore overwrites the header with a derived value) only when:

  • The header is absent — req.Header.Get(echo.HeaderXRealIP) == ""; or
  • IPExtractor is explicitly configured — c.Echo().IPExtractor != nil

The condition is FALSE — and the header is left unchanged — when the request arrives with an X-Real-IP header already set and IPExtractor is nil. Because Echo.New() leaves IPExtractor as nil, this is the out-of-the-box behaviour for every application that uses Proxy() or ProxyWithConfig() without extra configuration.

An attacker who sets X-Real-IP to any value causes Echo to forward exactly that value to the upstream, with no modification or validation.

The comment in the source code confirms intent and the security gap

The inline comment at line 351-352 explicitly states:

"Basically it's not good practice to unconditionally pass incoming x-real-ip header to upstream. However, for backward compatibility, legacy behavior is preserved unless you configure Echo#IPExtractor."

The framework is aware that the default is insecure and retains it for backward compatibility. No warning appears in the Proxy() or ProxyWithConfig() documentation, so operators who follow the standard setup example receive a silently insecure proxy configuration.

This is structurally identical to the documented insecurity in ip.go:27:

"Note: if you don't set Echo#IPExtractor explicitly, Echo fallback to legacy behavior, which is not a good choice."

Full execution chain

  1. Attacker sends GET /api/admin to the Echo proxy with header X-Real-IP: 203.0.113.1 (a trusted corporate IP)
  2. ToMiddleware() evaluates the guard at line 353: header is present (!= ""), IPExtractor is nil → condition is FALSE
  3. req.Header.Set is not called; the upstream request carries the original, attacker-supplied X-Real-IP: 203.0.113.1
  4. Upstream service checks X-Real-IP against its IP allowlist → finds 203.0.113.1 → grants access
  5. Attacker reaches an endpoint that should be restricted to the corporate IP range

Secondary impact path (audit poisoning):

  • All upstream log entries, rate-limit counters, and geo-restriction checks are evaluated against 203.0.113.1 rather than the real client IP, rendering audit trails and security analytics unreliable.

Proof of Concept

package main

import (
    "fmt"
    "log"
    "net/http"
    echo "github.com/labstack/echo/v5"
    "github.com/labstack/echo/v5/middleware"
)

func main() {
    // Upstream server: echoes back the X-Real-IP it received
    upstream := http.NewServeMux()
    upstream.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w,…
Record
GHSA-99jh-6h7p-pp36
CVSS 3.1
5.3 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-346
Updated
2026-11-02
NVD 5.3

Echo is a Go web framework. From 4.0.0 until 5.4.0, the Proxy middleware can preserve an attacker-supplied X-Real-IP header and forward it to an upstream service when Echo.IPExtractor is not configured. A remote client can therefore make upstream services receive a spoofed client address, undermining IP-based access controls, rate limiting, audit logging, or geographic restrictions that trust Echo's forwarded identity. This issue is fixed in Echo 5.4.0.

Record
CVE-2026-118651
CVSS 3.1
5.3 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-346
Updated
2026-11-02
OSV 5.3

Echo: Reverse Proxy Forwards Attacker-Supplied X-Real-IP to Upstream by Default

Echo is a Go web framework. From 4.0.0 until 5.4.0, the Proxy middleware can preserve an attacker-supplied X-Real-IP header and forward it to an upstream service when Echo.IPExtractor is not configured. A remote client can therefore make upstream services receive a spoofed client address, undermining IP-based access controls, rate limiting, audit logging, or geographic restrictions that trust Echo's forwarded identity. This issue is fixed in Echo 5.4.0.

Record
CVE-2026-118651
CVSS 3.1
5.3 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-346
Updated
2026-11-06
OSVDEBIAN-CVE-2026-118651 5.3

Echo is a Go web framework. From 4.0.0 until 5.4.0, the Proxy middleware can preserve an attacker-supplied X-Real-IP header and forward it to an upstream service when Echo.IPExtractor is not configured. A remote client can therefore make upstream services receive a spoofed client address, undermining IP-based access controls, rate limiting, audit logging, or geographic restrictions that trust Echo's forwarded identity. This issue is fixed in Echo 5.4.0.

Record
DEBIAN-CVE-2026-118651
CVSS 3.1
5.3 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Updated
2026-11-02
OSVGHSA-99jh-6h7p-pp36 5.3

Echo: Reverse Proxy Forwards Attacker-Supplied X-Real-IP to Upstream by Default

Summary

The Echo proxy middleware (middleware/proxy.go) preserves an incoming X-Real-IP header verbatim and forwards it to the upstream service when Echo#IPExtractor is not configured — which is the default. Because any HTTP client can supply an arbitrary X-Real-IP value, an attacker can cause Echo to relay a spoofed client IP address to every upstream service behind the proxy, undermining upstream IP-based access controls, rate limiting, audit logging, and geo-restriction.

Affected Component

  • middleware/proxy.go — ProxyConfig.ToMiddleware(), header-rewriting block (lines 351–355)

Description

The header-preservation condition passes spoofed values to upstream

ProxyConfig.ToMiddleware() (proxy.go:338-405) prepares forwarding headers before dispatching each request. The X-Real-IP rewrite logic at lines 351-355 reads:

// proxy.go:351-355
// Basically it's not good practice to unconditionally pass incoming x-real-ip header to upstream.
// However, for backward compatibility, legacy behavior is preserved unless you configure Echo#IPExtractor.
if req.Header.Get(echo.HeaderXRealIP) == "" || c.Echo().IPExtractor != nil {
    req.Header.Set(echo.HeaderXRealIP, c.RealIP())
}

The condition is TRUE (and therefore overwrites the header with a derived value) only when:

  • The header is absent — req.Header.Get(echo.HeaderXRealIP) == ""; or
  • IPExtractor is explicitly configured — c.Echo().IPExtractor != nil

The condition is FALSE — and the header is left unchanged — when the request arrives with an X-Real-IP header already set and IPExtractor is nil. Because Echo.New() leaves IPExtractor as nil, this is the out-of-the-box behaviour for every application that uses Proxy() or ProxyWithConfig() without extra configuration.

An attacker who sets X-Real-IP to any value causes Echo to forward exactly that value to the upstream, with no modification or validation.

The comment in the source code confirms intent and the security gap

The inline comment at line 351-352 explicitly states:

"Basically it's not good practice to unconditionally pass incoming x-real-ip header to upstream. However, for backward compatibility, legacy behavior is preserved unless you configure Echo#IPExtractor."

The framework is aware that the default is insecure and retains it for backward compatibility. No warning appears in the Proxy() or ProxyWithConfig() documentation, so operators who follow the standard setup example receive a silently insecure proxy configuration.

This is structurally identical to the documented insecurity in ip.go:27:

"Note: if you don't set Echo#IPExtractor explicitly, Echo fallback to legacy behavior, which is not a good choice."

Full execution chain

  1. Attacker sends GET /api/admin to the Echo proxy with header X-Real-IP: 203.0.113.1 (a trusted corporate IP)
  2. ToMiddleware() evaluates the guard at line 353: header is present (!= ""), IPExtractor is nil → condition is FALSE
  3. req.Header.Set is not called; the upstream request carries the original, attacker-supplied X-Real-IP: 203.0.113.1
  4. Upstream service checks X-Real-IP against its IP allowlist → finds 203.0.113.1 → grants access
  5. Attacker reaches an endpoint that should be restricted to the corporate IP range

Secondary impact path (audit poisoning):

  • All upstream log entries, rate-limit counters, and geo-restriction checks are evaluated against 203.0.113.1 rather than the real client IP, rendering audit trails and security analytics unreliable.

Proof of Concept

package main

import (
    "fmt"
    "log"
    "net/http"
    echo "github.com/labstack/echo/v5"
    "github.com/labstack/echo/v5/middleware"
)

func main() {
    // Upstream server: echoes back the X-Real-IP it received
    upstream := http.NewServeMux()
    upstream.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w,…
Record
GHSA-99jh-6h7p-pp36
CVSS 3.1
5.3 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-346
Updated
2026-11-06
OSVUBUNTU-CVE-2026-118651 5.3

Echo is a Go web framework. From 4.0.0 until 5.4.0, the Proxy middleware can preserve an attacker-supplied X-Real-IP header and forward it to an upstream service when Echo.IPExtractor is not configured. A remote client can therefore make upstream services receive a spoofed client address, undermining IP-based access controls, rate limiting, audit logging, or geographic restrictions that trust Echo's forwarded identity. This issue is fixed in Echo 5.4.0.

Record
UBUNTU-CVE-2026-118651
CVSS 3.1
5.3 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Updated
2026-11-05
OSVGO-2026-6875 No score

Reverse Proxy Forwards Attacker-Supplied X-Real-IP to Upstream by Default in github.com/labstack/echo

Reverse Proxy Forwards Attacker-Supplied X-Real-IP to Upstream by Default in github.com/labstack/echo

Record
GO-2026-6875
Updated
2026-11-06

Affected products

Affected packages

Affected packages
PackageAffectedFixed
github.com/labstack/echo/v5
Go
before 5.4.0
5.4.0
github.com/labstack/echo/v4
Go
4.0.0 to 4.16.2 None known
golang-github-labstack-echo
Debian:12
All versions, plus listed versions
4.11.1-14.11.1-24.12.0-14.2.1-3
None known
golang-github-labstack-echo
Debian:13
All versions, plus listed versions
4.12.0-1
None known
golang-github-labstack-echo
Debian:14
All versions, plus listed versions
4.12.0-1
None known
github.com/labstack/echo/v4
Go
4.0.0 and later None known
golang-github-labstack-echo.v2
Ubuntu:20.04:LTS
All versions, plus listed versions
2.2.0-1
None known
golang-github-labstack-echo.v3
Ubuntu:20.04:LTS
All versions, plus listed versions
3.3.5-1
None known
golang-github-labstack-echo
Ubuntu:22.04:LTS
All versions, plus listed versions
4.2.1-2
None known
golang-github-labstack-echo.v2
Ubuntu:22.04:LTS
All versions, plus listed versions
2.2.0-2
None known
Show 4 moreShow less
Affected packages
PackageAffectedFixed
golang-github-labstack-echo.v3
Ubuntu:22.04:LTS
All versions, plus listed versions
3.3.10-1
None known
golang-github-labstack-echo
Ubuntu:24.04:LTS
All versions, plus listed versions
4.11.1-2
None known
golang-github-labstack-echo
Ubuntu:26.10
All versions, plus listed versions
4.12.0-1
None known
golang-github-labstack-echo
Ubuntu:26.04:LTS
All versions, plus listed versions
4.12.0-1
None known

History

History
RecordedChangedSources
affected, aliasesOSV
factsOSV
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

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

In short

CVE-2026-118651 is a medium vulnerability (CVSS 5.3) in Labstack Echo, published October 28, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.21%, the 10th percentile. Fixed in github.com/labstack/echo/v5 5.4.0.

References

Show 4 moreShow less
This page doesn't list everything

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

MoveEnter Open