CVE-2026-118656
## 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`): ```go 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: ```go 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 } ``` 2. `AddTrailingSlash` does the same in the opposite direction at `middleware/slash.go:67`. 3. A request for `/%09/attacker.example/x/` has `url.Path` equal to `"/\t/attacker.example/x/"` (a literal TAB
Properties
- Severity
- medium
- Summary
- Echo has Open Redirect via Control-Character Prefix Defeating sanitizeURI
- Nvd fetched at
- 2026-10-28T23:43:43.157973+00:00
- Cvss severity
- MEDIUM
- Cvss score
- 6.1
- Retrieved at
- 2026-10-28T23:45:49+00:00
- Ghsa published
- 2026-10-28T21:04:22Z
- Source url
- https://github.com/advisories/GHSA-v753-g4cw-jm48
- Ghsa updated
- 2026-10-28T21:04:23Z
- Ghsa id
- GHSA-v753-g4cw-jm48
- Last source
- GitHub Advisory Database
- Score
- 6.1
- Cvss version
- 3.1
- Cve id
- CVE-2026-118656
- Cvss vector
- CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
- First seen by Signal
- 2026-10-28T23:44:40+00:00
- Is ghsa only
- false
- Vector
- CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
- Published at
- 2026-10-28T21:16:55.550
- Last modified
- 2026-10-28T21:16:55.550
Related Entities (5)
AFFECTS (2)
VULNERABLE_TO (2)
HAS_WEAKNESS (1)
Explore deeper with Ninja Signal's threat intelligence graph