GHSA-p64j-f4x9-wq66 - Ech0's OAuth redirect URI validation ignores path component, enables exchange-co

📡 GitHub-Advisory · 2026-05-07

GHSA-p64j-f4x9-wq66 - Ech0's OAuth redirect URI validation ignores path component, enables exchange-co

GHSA-p64j-f4x9-wq66 HIGH go/github.com/lin-snow/Ech0

CVE:

Summary

parseAndValidateClientRedirect at internal/service/auth/auth.go:448 validates OAuth client-redirect URIs by comparing only scheme and host against the admin-configured allowlist. Path, query, and fragment are ignored. The initiator at /oauth/:provider/login embeds the caller-supplied redirect_uri verbatim into the signed state JWT without any validation at login time. Alice submits a crafted redirect_uri whose host matches an allowed origin but whose path points to any page on that host. After the provider exchange, Ech0 redirects the victim to the attacker-chosen path with the one-time exchange code in the query string. If the chosen path leaks the URL via Referer, analytics, or an open redirect, the attacker trades the code at POST /api/auth/exchange for the victim's access and refresh tokens. RFC 6749 §3.1.2 requires exact redirect URI matching.

Details

Validation at internal/service/auth/auth.go:448:

matched := false
for _, item := range allowed {
    allowURL, parseErr := url.Parse(strings.TrimSpace(item))
    if parseErr != nil || allowURL == nil || allowURL.Host == "" {
        continue
    }
    if strings.EqualFold(redirectURL.Scheme, allowURL.Scheme) &&
       strings.EqualFold(redirectURL.Host, allowURL.Host) {
        matched = true
        break
    }
}

Scheme and host compared via EqualFold. Path, query, fragment all ignored. An allowlist entry of https://myecho.example.com/dashboard matches every https://myecho.example.com/<anything> the attacker sends.

Login flow at internal/service/auth/auth.go:141 (GetOAuthLoginURL) and the handler at internal/handler/auth/oauth.go:43:

redirectURI := ctx.Query("redirect_uri")
redirectURL, err := h.authService.GetOAuthLoginURL(provider, redirectURI)
// ...
ctx.Redirect(302, redirectURL)

No validation at login. The raw redirect_uri query parameter is passed to GetOAuthLoginURL, which encodes it into the signed state JWT alongside the provider nam


📌 来源: GitHub-Advisory | 📅 2026-05-07

[!] CONTACT_CHANNELS

如需商务合作、技术咨询或漏洞反馈,请通过以下离岸节点联系作者。

> PING_AUTHOR (@A1RedTeam)