CVE-2026-79662
Ech0 before 4.7.3 OAuth Redirect URI Validation Bypass
Ech0 through 4.5.6 contains an OAuth redirect URI validation vulnerability in parseAndValidateClientRedirect (internal/service/auth/auth.go) that compares only the scheme and host of the client-supplied redirect_uri against the admin-configured allowlist, ignoring path, query, and fragment components. The redirect_uri is embedded into the signed state JWT at login time without validation. An attacker can craft a redirect_uri whose host matches an allowed origin but whose path is attacker-influenced; after the OAuth exchange the victim is redirected to that path with a one-time exchange code in the query string. If the code leaks (e.g., via Referer, analytics, or an open redirect on that host), the attacker can trade it at the public POST /api/auth/exchange endpoint for the victim's access and refresh tokens. Fixed in 4.7.3.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- High
- Privileges needed
- None
- User interaction
- Passive
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
8.8
Ech0 before 4.7.3 OAuth Redirect URI Validation Bypass
Ech0 through 4.5.6 contains an OAuth redirect URI validation vulnerability in parseAndValidateClientRedirect (internal/service/auth/auth.go) that compares only the scheme and host of the client-supplied redirect_uri against the admin-configured allowlist, ignoring path, query, and fragment components. The redirect_uri is embedded into the signed state JWT at login time without validation. An attacker can craft a redirect_uri whose host matches an allowed origin but whose path is attacker-influenced; after the OAuth exchange the victim is redirected to that path with a one-time exchange code in the query string. If the code leaks (e.g., via Referer, analytics, or an open redirect on that host), the attacker can trade it at the public POST /api/auth/exchange endpoint for the victim's access and refresh tokens. Fixed in 4.7.3.
- Record
CVE-2026-79662- CVSS 4.0
- 8.8 High
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:P/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N - CVSS 3.1
- 8.0 High
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:N - Weakness
- CWE-601
- Updated
- 2026-11-02
EUVDEUVD-2026-65452
8.8
Ech0 through 4.5.6 contains an OAuth redirect URI validation vulnerability in parseAndValidateClientRedirect (internal/service/auth/auth.go) that compares only the scheme and host of the client-supplied redirect_uri against the admin-configured allowlist, ignoring path, query, and fragment components. The redirect_uri is embedded into the signed state JWT at login time without validation. An attacker can craft a redirect_uri whose host matches an allowed origin but whose path is attacker-influenced; after the OAuth exchange the victim is redirected to that path with a one-time exchange code in the query string. If the code leaks (e.g., via Referer, analytics, or an open redirect on that host), the attacker can trade it at the public POST /api/auth/exchange endpoint for the victim's access and refresh tokens. Fixed in 4.7.3.
- Record
EUVD-2026-65452- CVSS 4.0
- 8.8 High
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:P/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-m5w8-4879-f4pc
8.8
Ech0 through 4.5.6 contains an OAuth redirect URI validation vulnerability in...
Ech0 through 4.5.6 contains an OAuth redirect URI validation vulnerability in parseAndValidateClientRedirect (internal/service/auth/auth.go) that compares only the scheme and host of the client-supplied redirect_uri against the admin-configured allowlist, ignoring path, query, and fragment components. The redirect_uri is embedded into the signed state JWT at login time without validation. An attacker can craft a redirect_uri whose host matches an allowed origin but whose path is attacker-influenced; after the OAuth exchange the victim is redirected to that path with a one-time exchange code in the query string. If the code leaks (e.g., via Referer, analytics, or an open redirect on that host), the attacker can trade it at the public POST /api/auth/exchange endpoint for the victim's access and refresh tokens. Fixed in 4.7.3.
- Record
GHSA-m5w8-4879-f4pc- CVSS 4.0
- 8.8 High
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:P/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 8.0 High
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:N - Weakness
- CWE-601
- Updated
- 2026-11-02
GitHub AdvisoriesGHSA-p64j-f4x9-wq66
8.0
Ech0's OAuth redirect URI validation ignores path component, enables exchange-code theft
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 name and nonce. The state JWT travels through the OAuth provider and returns on the callback.
At callback time, parseAndValidateClientRedirect(oauthState.Redirect) fires at internal/service/auth/auth.go:372 and :427 inside the callback handler chain. Scheme and host are the only gates on the attacker-chosen URI.
After validation, the server generates a one-time exchange code and redirects the browser to the attacker-chosen path:
302 Location: https://myecho.example.com/<attacker-path>?code=<one-time-exchange-code>
The code is valid at the public endpoint POST /api/auth/exchange for up to 60 seconds (single-use). An attacker who reads the code from the URL trades it for the victim's access token and refresh token.
Proof of Concept
Default install with OAuth2 configured. Admin allows https://myecho.example.com/dashboard as the return URL; Alice sends a crafted login link whose redirect points elsewhere on the same host:
import requests, urllib.parse, base64, json
TARGET = "http://localhost:8300"
# Admin setup: enable OAuth with one allowed return URL (dashboard).
owner = requests.post(f"{TARGET}/api/login",
json={"username": "owner", "password": "owner-pw"}
).json()["data"]["access_token"]
requests.put(f"{TARGET}/api/oauth2/settings",
headers={"Authorization": f"Bearer {owner}",
"content-type": "application/json"},
json={"enable": True, "provider": "github",
"client_id": "poc-client-id", "client_secret": "poc-client-secret",
"redirect_uri": f"{TARGET}/oauth/github/callback",
"scopes": ["read:user"],
"auth_url": "https://github.com/login/oauth/authorize",
"token_url": "https://github.com/login/oauth/access_token",
"user_info_url": "https://api.github.com/user",
"auth_redirect_allowed_return_urls":…
- Record
GHSA-p64j-f4x9-wq66- CVSS 3.1
- 8.0 High
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:N - Weakness
- CWE-601, CWE-1173
- Updated
- 2026-11-02
NVD
8.8
Ech0 through 4.5.6 contains an OAuth redirect URI validation vulnerability in parseAndValidateClientRedirect (internal/service/auth/auth.go) that compares only the scheme and host of the client-supplied redirect_uri against the admin-configured allowlist, ignoring path, query, and fragment components. The redirect_uri is embedded into the signed state JWT at login time without validation. An attacker can craft a redirect_uri whose host matches an allowed origin but whose path is attacker-influenced; after the OAuth exchange the victim is redirected to that path with a one-time exchange code in the query string. If the code leaks (e.g., via Referer, analytics, or an open redirect on that host), the attacker can trade it at the public POST /api/auth/exchange endpoint for the victim's access and refresh tokens. Fixed in 4.7.3.
- Record
CVE-2026-79662- CVSS 4.0
- 8.8 High
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:P/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 8.0 High
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:N - Weakness
- CWE-601
- Updated
- 2026-11-02
OSV
8.8
Ech0 before 4.7.3 OAuth Redirect URI Validation Bypass
Ech0 through 4.5.6 contains an OAuth redirect URI validation vulnerability in parseAndValidateClientRedirect (internal/service/auth/auth.go) that compares only the scheme and host of the client-supplied redirect_uri against the admin-configured allowlist, ignoring path, query, and fragment components. The redirect_uri is embedded into the signed state JWT at login time without validation. An attacker can craft a redirect_uri whose host matches an allowed origin but whose path is attacker-influenced; after the OAuth exchange the victim is redirected to that path with a one-time exchange code in the query string. If the code leaks (e.g., via Referer, analytics, or an open redirect on that host), the attacker can trade it at the public POST /api/auth/exchange endpoint for the victim's access and refresh tokens. Fixed in 4.7.3.
- Record
CVE-2026-79662- CVSS 4.0
- 8.8 High
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:P/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N - Weakness
- CWE-601
- Updated
- 2026-11-02
OSVGHSA-p64j-f4x9-wq66
8.0
Ech0's OAuth redirect URI validation ignores path component, enables exchange-code theft
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 name and nonce. The state JWT travels through the OAuth provider and returns on the callback.
At callback time, parseAndValidateClientRedirect(oauthState.Redirect) fires at internal/service/auth/auth.go:372 and :427 inside the callback handler chain. Scheme and host are the only gates on the attacker-chosen URI.
After validation, the server generates a one-time exchange code and redirects the browser to the attacker-chosen path:
302 Location: https://myecho.example.com/<attacker-path>?code=<one-time-exchange-code>
The code is valid at the public endpoint POST /api/auth/exchange for up to 60 seconds (single-use). An attacker who reads the code from the URL trades it for the victim's access token and refresh token.
Proof of Concept
Default install with OAuth2 configured. Admin allows https://myecho.example.com/dashboard as the return URL; Alice sends a crafted login link whose redirect points elsewhere on the same host:
import requests, urllib.parse, base64, json
TARGET = "http://localhost:8300"
# Admin setup: enable OAuth with one allowed return URL (dashboard).
owner = requests.post(f"{TARGET}/api/login",
json={"username": "owner", "password": "owner-pw"}
).json()["data"]["access_token"]
requests.put(f"{TARGET}/api/oauth2/settings",
headers={"Authorization": f"Bearer {owner}",
"content-type": "application/json"},
json={"enable": True, "provider": "github",
"client_id": "poc-client-id", "client_secret": "poc-client-secret",
"redirect_uri": f"{TARGET}/oauth/github/callback",
"scopes": ["read:user"],
"auth_url": "https://github.com/login/oauth/authorize",
"token_url": "https://github.com/login/oauth/access_token",
"user_info_url": "https://api.github.com/user",
"auth_redirect_allowed_return_urls":…
- Record
GHSA-p64j-f4x9-wq66- CVSS 3.1
- 8.0 High
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:N - Weakness
- CWE-1173, CWE-601
- Updated
- 2026-11-02
OSVGO-2026-5531 No score
Ech0's OAuth redirect URI validation ignores path component, enables exchange-code theft in github.com/lin-snow/ech0
Ech0's OAuth redirect URI validation ignores path component, enables exchange-code theft in github.com/lin-snow/ech0
- Record
GO-2026-5531- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
github.com/lin-snow/Ech0Go |
before 1.4.8-0.20260503040728-a7e8b8e84bd1 | 1.4.8-0.20260503040728-a7e8b8e84bd1 |
github.com/lin-snow/ech0Go |
before 1.4.8-0.20260503040728-a7e8b8e84bd1 | 1.4.8-0.20260503040728-a7e8b8e84bd1 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-79662 is a high vulnerability (CVSS 8.8) in Lin-snow Ech0, published May 7, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.32%, the 25th percentile. Fixed in github.com/lin-snow/Ech0 1.4.8-0.20260503040728-a7e8b8e84bd1.
References
github.com/lin-snow/Ech0/security/advisories/GHSA-p64j-f4x9-wq66
vulncheck.com/advisories/ech0-before-oauth-redirect-uri-validation-bypass
nvd.nist.gov/vuln/detail/CVE-2026-79662
github.com/advisories/GHSA-m5w8-4879-f4pc
github.com/lin-snow/Ech0/commit/a7e8b8e84bd1e3db090dfb720f2c6c433356b442
github.com/advisories/GHSA-p64j-f4x9-wq66
github.com/CVEProject/cvelistV5/tree/main/cves/2026/79xxx/CVE-2026-79662.json
github.com/lin-snow/Ech0
Left out here: the rest of 2 source descriptions. The JSON record has them.