Every CVE Search/ Get API key

CVE-2026-118656

Echo: Open Redirect via Control-Character Prefix Defeating sanitizeURI

6.1 MediumFix available

Echo is a Go web framework. Prior to 4.16.0 and 5.4.0, sanitizeURI checks only the first two bytes of a redirect target before deciding whether it begins with an absolute-path separator pair. When AddTrailingSlash or RemoveTrailingSlash is configured with a redirect status, a slash, TAB, separator path form can evade the guard, be emitted in the Location header, and be normalized by a browser into an attacker-controlled host. This issue is fixed in 4.16.0 and 5.4.0.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
Required

What an attacker can affect

Confidentiality
Low
Integrity
Low
Availability
None

Exploit likelihood

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

What each source reports

CVE List Score used 6.1

Echo: Open Redirect via Control-Character Prefix Defeating sanitizeURI

Echo is a Go web framework. Prior to 4.16.0 and 5.4.0, sanitizeURI checks only the first two bytes of a redirect target before deciding whether it begins with an absolute-path separator pair. When AddTrailingSlash or RemoveTrailingSlash is configured with a redirect status, a slash, TAB, separator path form can evade the guard, be emitted in the Location header, and be normalized by a browser into an attacker-controlled host. This issue is fixed in 4.16.0 and 5.4.0.

Record
CVE-2026-118656
CVSS 3.1
6.1 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Weakness
CWE-601
Updated
2026-11-02
EUVDEUVD-2026-112463 6.1

Echo is a Go web framework. Prior to 4.16.0 and 5.4.0, sanitizeURI checks only the first two bytes of a redirect target before deciding whether it begins with an absolute-path separator pair. When AddTrailingSlash or RemoveTrailingSlash is configured with a redirect status, a slash, TAB, separator path form can evade the guard, be emitted in the Location header, and be normalized by a browser into an attacker-controlled host. This issue is fixed in 4.16.0 and 5.4.0.

Record
EUVD-2026-112463
CVSS 3.1
6.1 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-v753-g4cw-jm48 6.1

Echo has Open Redirect via Control-Character Prefix Defeating sanitizeURI

Summary

Echo's dedicated open-redirect guard, sanitizeURI, decides whether a redirect target is a local path by inspecting exactly two byte positions: uri[0] and uri[1]. If the value begins with a control character such as a tab or a newline, followed by a separator pair, the guard does not fire and the value is written to the Location header unchanged.

Browsers remove tab and newline characters from URLs before parsing them, and treat a backslash as a forward slash for HTTP and HTTPS URLs. A Location value of /\t/attacker.example is therefore resolved by the browser as an absolute URL on attacker.example. Confirmed end to end in a headless browser.

Technical background

The guard

middleware/slash.go:144 (duplicated verbatim at echo.go:958):

func sanitizeURI(uri string) string {
	// double slash `\\`, `//` or even `\/` is absolute uri for browsers and by redirecting request to that uri
	// we are vulnerable to open redirect attack. so replace all slashes from the beginning with single slash
	if len(uri) > 1 && (uri[0] == '\\' || uri[0] == '/') && (uri[1] == '\\' || uri[1] == '/') {
		uri = "/" + strings.TrimLeft(uri, `/\`)
	}
	return uri
}

The condition is anchored at absolute offsets 0 and 1. It cannot see a separator that has been shifted by one byte.

Data flow

  1. RemoveTrailingSlash (middleware/slash.go:112-140) reads url.Path, which net/http has already percent-decoded, strips the trailing slash, and appends the raw query string:
path := url.Path
...
if l > 0 && strings.HasSuffix(path, "/") {
    path = path[:l]
    uri := path
    if qs != "" {
        uri += "?" + qs
    }
    if config.RedirectCode != 0 {
        return c.Redirect(config.RedirectCode, sanitizeURI(uri))   // line 132
    }
  1. AddTrailingSlash does the same in the opposite direction at middleware/slash.go:67.

  2. A request for /%09/attacker.example/x/ has url.Path equal to "/\t/attacker.example/x/" (a literal TAB byte). sanitizeURI evaluates uri[0] == '\t', the condition is false, and the value passes through untouched.

  3. Context.Redirect (context.go:735) writes it to the Location header. Go's header writer removes CR and LF but leaves TAB, which is all that is required.

Conditional analysis

  • Guard: uri[0] and uri[1] are separators. Trust boundary: server-side sanitization of attacker-influenced path data.
  • Bypass: place a single control byte before the separator pair. The separator moves to index 1 and the guard's second condition (uri[1] being a separator) is never reached because the first condition (uri[0] being a separator) already failed.
  • Browser-side trust boundary: the client's URL parser. It is adversary favourable: control characters are stripped and backslashes are normalized before scheme and authority parsing. The attacker does not need any server-side weakness beyond producing the malformed Location.

Note that the newline variant does not survive: net/http replaces CR and LF in header values. TAB does survive, and TAB alone is sufficient because the browser strips it.

Proof of concept

Attached PoC: ECHO-2026-002_poc.zip (in this directory). Extract it and follow ECHO-2026-002/README.md for the full walkthrough. The archive contains a self-contained Go module (go.mod, go.sum, main.go, README.md).

ECHO-2026-002_poc.zip

Quick start:

unzip ECHO-2026-002_poc.zip
cd ECHO-2026-002
# edit go.mod: point the replace directive at your Echo checkout
sed -i 's|=> .*|=> /absolute/path/to/echo|' go.mod
GOFLAGS=-mod=mod go run .          # in-process check
GOFLAGS=-mod=mod go run . -serve   # real listener on 127.0.0.1:18002

Environment used for verification

  • OS: Linux 6.18.33.2-microsoft-standard-WSL2, x86_64
  • Go: go1.27.0 linux/amd64
  • Target: Echo v5.3.1 (module github.com/labstack/echo/v5)
  • Browser: headless Chromium…
Record
GHSA-v753-g4cw-jm48
CVSS 3.1
6.1 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Weakness
CWE-601
Updated
2026-11-02
NVD 6.1

Echo is a Go web framework. Prior to 4.16.0 and 5.4.0, sanitizeURI checks only the first two bytes of a redirect target before deciding whether it begins with an absolute-path separator pair. When AddTrailingSlash or RemoveTrailingSlash is configured with a redirect status, a slash, TAB, separator path form can evade the guard, be emitted in the Location header, and be normalized by a browser into an attacker-controlled host. This issue is fixed in 4.16.0 and 5.4.0.

Record
CVE-2026-118656
CVSS 3.1
6.1 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Weakness
CWE-601
Updated
2026-11-02
OSV 6.1

Echo: Open Redirect via Control-Character Prefix Defeating sanitizeURI

Echo is a Go web framework. Prior to 4.16.0 and 5.4.0, sanitizeURI checks only the first two bytes of a redirect target before deciding whether it begins with an absolute-path separator pair. When AddTrailingSlash or RemoveTrailingSlash is configured with a redirect status, a slash, TAB, separator path form can evade the guard, be emitted in the Location header, and be normalized by a browser into an attacker-controlled host. This issue is fixed in 4.16.0 and 5.4.0.

Record
CVE-2026-118656
CVSS 3.1
6.1 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Weakness
CWE-601
Updated
2026-11-06
OSVDEBIAN-CVE-2026-118656 6.1

Echo is a Go web framework. Prior to 4.16.0 and 5.4.0, sanitizeURI checks only the first two bytes of a redirect target before deciding whether it begins with an absolute-path separator pair. When AddTrailingSlash or RemoveTrailingSlash is configured with a redirect status, a slash, TAB, separator path form can evade the guard, be emitted in the Location header, and be normalized by a browser into an attacker-controlled host. This issue is fixed in 4.16.0 and 5.4.0.

Record
DEBIAN-CVE-2026-118656
CVSS 3.1
6.1 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Updated
2026-11-02
OSVGHSA-v753-g4cw-jm48 6.1

Echo has Open Redirect via Control-Character Prefix Defeating sanitizeURI

Summary

Echo's dedicated open-redirect guard, sanitizeURI, decides whether a redirect target is a local path by inspecting exactly two byte positions: uri[0] and uri[1]. If the value begins with a control character such as a tab or a newline, followed by a separator pair, the guard does not fire and the value is written to the Location header unchanged.

Browsers remove tab and newline characters from URLs before parsing them, and treat a backslash as a forward slash for HTTP and HTTPS URLs. A Location value of /\t/attacker.example is therefore resolved by the browser as an absolute URL on attacker.example. Confirmed end to end in a headless browser.

Technical background

The guard

middleware/slash.go:144 (duplicated verbatim at echo.go:958):

func sanitizeURI(uri string) string {
	// double slash `\\`, `//` or even `\/` is absolute uri for browsers and by redirecting request to that uri
	// we are vulnerable to open redirect attack. so replace all slashes from the beginning with single slash
	if len(uri) > 1 && (uri[0] == '\\' || uri[0] == '/') && (uri[1] == '\\' || uri[1] == '/') {
		uri = "/" + strings.TrimLeft(uri, `/\`)
	}
	return uri
}

The condition is anchored at absolute offsets 0 and 1. It cannot see a separator that has been shifted by one byte.

Data flow

  1. RemoveTrailingSlash (middleware/slash.go:112-140) reads url.Path, which net/http has already percent-decoded, strips the trailing slash, and appends the raw query string:
path := url.Path
...
if l > 0 && strings.HasSuffix(path, "/") {
    path = path[:l]
    uri := path
    if qs != "" {
        uri += "?" + qs
    }
    if config.RedirectCode != 0 {
        return c.Redirect(config.RedirectCode, sanitizeURI(uri))   // line 132
    }
  1. AddTrailingSlash does the same in the opposite direction at middleware/slash.go:67.

  2. A request for /%09/attacker.example/x/ has url.Path equal to "/\t/attacker.example/x/" (a literal TAB byte). sanitizeURI evaluates uri[0] == '\t', the condition is false, and the value passes through untouched.

  3. Context.Redirect (context.go:735) writes it to the Location header. Go's header writer removes CR and LF but leaves TAB, which is all that is required.

Conditional analysis

  • Guard: uri[0] and uri[1] are separators. Trust boundary: server-side sanitization of attacker-influenced path data.
  • Bypass: place a single control byte before the separator pair. The separator moves to index 1 and the guard's second condition (uri[1] being a separator) is never reached because the first condition (uri[0] being a separator) already failed.
  • Browser-side trust boundary: the client's URL parser. It is adversary favourable: control characters are stripped and backslashes are normalized before scheme and authority parsing. The attacker does not need any server-side weakness beyond producing the malformed Location.

Note that the newline variant does not survive: net/http replaces CR and LF in header values. TAB does survive, and TAB alone is sufficient because the browser strips it.

Proof of concept

Attached PoC: ECHO-2026-002_poc.zip (in this directory). Extract it and follow ECHO-2026-002/README.md for the full walkthrough. The archive contains a self-contained Go module (go.mod, go.sum, main.go, README.md).

ECHO-2026-002_poc.zip

Quick start:

unzip ECHO-2026-002_poc.zip
cd ECHO-2026-002
# edit go.mod: point the replace directive at your Echo checkout
sed -i 's|=> .*|=> /absolute/path/to/echo|' go.mod
GOFLAGS=-mod=mod go run .          # in-process check
GOFLAGS=-mod=mod go run . -serve   # real listener on 127.0.0.1:18002

Environment used for verification

  • OS: Linux 6.18.33.2-microsoft-standard-WSL2, x86_64
  • Go: go1.27.0 linux/amd64
  • Target: Echo v5.3.1 (module github.com/labstack/echo/v5)
  • Browser: headless Chromium…
Record
GHSA-v753-g4cw-jm48
CVSS 3.1
6.1 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Weakness
CWE-601
Updated
2026-11-06
OSVUBUNTU-CVE-2026-118656 6.1

Echo is a Go web framework. Prior to 4.16.0 and 5.4.0, sanitizeURI checks only the first two bytes of a redirect target before deciding whether it begins with an absolute-path separator pair. When AddTrailingSlash or RemoveTrailingSlash is configured with a redirect status, a slash, TAB, separator path form can evade the guard, be emitted in the Location header, and be normalized by a browser into an attacker-controlled host. This issue is fixed in 4.16.0 and 5.4.0.

Record
UBUNTU-CVE-2026-118656
CVSS 3.1
6.1 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Updated
2026-11-05
OSVGO-2026-6883 No score

Echo has Open Redirect via Control-Character Prefix Defeating sanitizeURI in github.com/labstack/echo

Echo has Open Redirect via Control-Character Prefix Defeating sanitizeURI in github.com/labstack/echo

Record
GO-2026-6883
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
before 4.16.0
4.16.0
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
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
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-118656 is a medium vulnerability (CVSS 6.1) 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.20%, the 9th percentile. Fixed in github.com/labstack/echo/v5 5.4.0.

References

Show 6 moreShow less
This page doesn't list everything

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

MoveEnter Open