GHSA-23wf-92cp-8pcj: Medium severity go/github.com/labstack/echo/v4 vulnerability
Summary
The c.Scheme() method in Echo (context.go:162-181) trusts the X-Forwarded-Proto, X-Forwarded-Protocol, and X-Url-Scheme request headers without validating that the value is http or https. The WWWRedirect() and NonWWWRedirect() middlewares use this unsanitized scheme to construct redirect URLs, allowing an attacker to inject arbitrary URI schemes into the Location response header.
Affected Components
- context.go:162-181 - Scheme() method returns attacker-controlled value verbatim - middleware/redirect.go:172-184 - redirectWWW/redirectNonWWW use unsanitized scheme
Proof of Concept
GET /path HTTP/1.1 Host: example.com X-Forwarded-Proto: javascript
Response: HTTP/1.1 301 Moved Permanently Location: javascript://www.example.com/path
Confirmed injectable schemes: javascript, data, vbscript, file, ftp, ssh, telnet, gopher.
Only WWWRedirect() and NonWWWRedirect() (and WithConfig variants) are affected. HTTPSRedirect, HTTPSWWWRedirect, HTTPSNonWWWRedirect are NOT affected (they hardcode https://).
Impact
- Open redirect to arbitrary scheme URLs when app is not behind a proxy that strips X-Forwarded-Proto - Cache poisoning when behind a CDN that caches redirect responses keyed by path - file:// scheme injection could trigger file access in some browser configurations
Suggested Fix
Whitelist scheme in c.Scheme() to only return http or https:
go func (c Context) Scheme() string { if c.IsTLS() { return "https" } if scheme := c.request.Header.Get(HeaderXForwardedProto); scheme != "" { scheme = strings.ToLower(strings.TrimSpace(scheme)) if scheme == "https" { return "https" } } return "http" }
Disclosure
Source code review, manually verified with actual HTTP server. Tested on Echo v5.0.4 (latest master).
Patches
Fixed in github.com/labstack/echo/v5 v5.1.1 and github.com/labstack/echo/v4 v4.15.2. Context.Scheme() now accepts only http, https, ws or wss from the X-Forwarded-Proto, X-Forwarded-Protocol and X-Url-Scheme headers, and falls back to http for any other value (#2953).
Workarounds
Upgrade to a patched version. If you cannot upgrade, have your edge proxy overwrite or remove the X-Forwarded-Proto, X-Forwarded-Protocol and X-Url-Scheme request headers.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
go/github.com/labstack/echo/v4to a version that resolves this vulnerability.Fixed in 4.15.2 - Upgrade
Upgrade
go/github.com/labstack/echo/v5to a version that resolves this vulnerability.Fixed in 5.1.1 - Upgrade
Upgrade
github.com/labstack/echo/v5to a version that resolves this vulnerability.Fixed in v5.1.1 - Upgrade
Upgrade
github.com/labstack/echo/v4to a version that resolves this vulnerability.Fixed in v4.15.2 - Configuration
Whitelist the scheme in c.Scheme() so it only returns http or https.
Echo Context.Scheme() Forwarded scheme validation = http or https - Compensating control
If upgrading is not possible, have the edge proxy overwrite or remove the X-Forwarded-Proto, X-Forwarded-Protocol, and X-Url-Scheme request headers.
Event History
Frequently Asked Questions
Which redirect middleware configurations are affected?
Only WWWRedirect() and NonWWWRedirect(), including their WithConfig variants, are affected. HTTPSRedirect, HTTPSWWWRedirect, and HTTPSNonWWWRedirect are not affected because they hardcode the https:// scheme.
What does an attacker need to exploit this issue?
An attacker can send a request containing X-Forwarded-Proto, X-Forwarded-Protocol, or X-Url-Scheme with an arbitrary scheme value while an affected redirect middleware is in use. No authentication is required, but the vulnerable redirect must be triggered.
When is an application exposed to the unsafe redirect behavior?
Exposure exists when the application uses WWWRedirect or NonWWWRedirect and receives these forwarded-scheme headers without a proxy stripping them. The Scheme() method returns the supplied header value verbatim, and the redirect middleware uses it in the Location header.
What can be done if an immediate code update is not possible?
Use one of the HTTPS redirect middlewares where suitable, since they construct redirects with a hardcoded https:// scheme. Deploying behind a proxy that strips untrusted forwarded-scheme headers also prevents those values from reaching the application.