Severity by source
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:P/VC:N/VI:N/VA:N/SC:L/SI:N/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
Primary rating from GitHub Advisory · only source for this CVE.
CVSS VectorGitHub Advisory
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:P/VC:N/VI:N/VA:N/SC:L/SI:N/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
Lifecycle Timeline
4DescriptionGitHub Advisory
Refresh Token Leaked via URL Query Parameter in OAuth Provider Callback
Summary
The auth service's OAuth provider callback flow places the refresh token directly into the redirect URL as a query parameter. Refresh tokens in URLs are logged in browser history, server access logs, HTTP Referer headers, and proxy/CDN logs.
Note that the refresh token is one-time use and all of these leak vectors are on owned infrastructure or services integrated by the application developer.
Affected Component
- Repository:
github.com/nhost/nhost - Service:
services/auth - File:
services/auth/go/controller/sign_in_provider_callback_get.go - Function:
signinProviderProviderCallback(lines 257-261)
Root Cause
In sign_in_provider_callback_get.go:257-261, after successful OAuth sign-in, the refresh token is appended as a URL query parameter:
if session != nil {
values := redirectTo.Query()
values.Add("refreshToken", session.RefreshToken)
redirectTo.RawQuery = values.Encode()
}This results in a redirect like:
HTTP/1.1 302 Found
Location: https://myapp.com/callback?refreshToken=a1b2c3d4-e5f6-7890-abcd-ef1234567890Proof of Concept
Step 1: Initiate OAuth login
GET /signin/provider/github?redirectTo=https://myapp.com/callbackStep 2: Complete OAuth flow with provider
Step 3: Auth service redirects with token in URL
HTTP/1.1 302 Found
Location: https://myapp.com/callback?refreshToken=a1b2c3d4-e5f6-7890-abcd-ef1234567890Step 4: Token is now visible in owned infrastructure and services:
Browser History:
# User's browser history now contains the refresh tokenHTTP Referer Header:
# If the callback page loads ANY external resource (image, script, etc.):
GET /resource.js HTTP/1.1
Host: cdn.example.com
Referer: https://myapp.com/callback?refreshToken=a1b2c3d4-e5f6-...
# Note: modern browsers default to strict-origin-when-cross-origin policy,
# which strips query parameters from cross-origin Referer headers.
# Additionally, the Referer is only sent to services integrated by the
# application developer (analytics, CDNs, etc.), not arbitrary third parties.Server Access Logs:
# Reverse proxy, CDN, or load balancer logs on owned infrastructure:
2026-03-08 12:00:00 GET /callback?refreshToken=a1b2c3d4-e5f6-... 200Step 5: Attacker uses stolen refresh token
# Exchange stolen refresh token for new access token
curl -X POST https://auth.nhost.run/v1/token \
-H 'Content-Type: application/json' \
-d '{"refreshToken": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}'
# Note: refresh tokens are one-time use, so this only works if the
# legitimate client has not already consumed the token and if the attacker has
# compromised your infrastructure to get access to this informationImpact
- Session Hijacking: Anyone who obtains the token before it is consumed by the legitimate client can generate new access tokens, though the refresh token is one-time use and cannot be reused after consumption.
- Leak Vectors: URL query parameters are visible in owned infrastructure and integrated services:
- Browser history (local access)
- HTTP Referer headers (mitigated by modern browser default referrer policies; only sent to developer-integrated services)
- Server access logs (owned infrastructure)
- Proxy/CDN/WAF logs (owned infrastructure)
- Affects All OAuth Providers: Every OAuth provider flow (GitHub, Google, Apple, etc.) goes through the same callback handler.
Fix
Implemented PKCE (Proof Key for Code Exchange) for the OAuth flow. With PKCE, the authorization code cannot be exchanged without the code_verifier that only the original client possesses, preventing token misuse even if the URL is logged.
See: https://docs.nhost.io/products/auth/pkce/
Resources
- OWASP: Session Management - Token Transport: "Session tokens should not be transported in the URL"
- RFC 6749 Section 10.3: "Access tokens and refresh tokens MUST NOT be included in the redirect URI"
- CWE-598: Use of GET Request Method With Sensitive Query Strings
- CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
AnalysisAI
Nhost auth service exposes OAuth refresh tokens in redirect URL query parameters, allowing access to browser history, server logs, and proxy logs on owned infrastructure. While refresh tokens are single-use and leak vectors are primarily confined to developer-controlled systems, the vulnerability violates RFC 6749 token transport requirements and enables session hijacking if logs are accessed before the token is legitimately consumed. All OAuth providers (GitHub, Google, Apple) are affected equally through the same vulnerable callback handler.
Technical ContextAI
The vulnerability exists in Nhost's OAuth provider callback implementation (services/auth/go/controller/sign_in_provider_callback_get.go, lines 257-261), where refresh tokens are appended directly to redirect URLs as query parameters. This violates RFC 6749 Section 10.3 (Access tokens and refresh tokens MUST NOT be included in the redirect URI) and represents CWE-598 (Use of GET Request Method With Sensitive Query Strings) and CWE-200 (Exposure of Sensitive Information). The root cause is improper token transport mechanism selection; URL query parameters are HTTP-level data visible to proxies, CDNs, load balancers, and logged by reverse proxies on owned infrastructure. The vulnerability affects all OAuth flows supported by Nhost (GitHub, Google, Apple, Microsoft) because they all route through the same callback handler. The fix implements PKCE (Proof Key for Code Exchange), which exchanges the authorization code for tokens server-side without exposing refresh tokens in URLs.
RemediationAI
Upgrade Nhost auth service to a patched version implementing PKCE (Proof Key for Code Exchange) as documented at https://docs.nhost.io/products/auth/pkce/. PKCE enables server-side token exchange without exposing refresh tokens in redirect URLs, eliminating the leak vector entirely. For deployments unable to upgrade immediately, implement mitigations at the infrastructure level: restrict access to reverse proxy, CDN, and WAF logs containing sensitive query parameters; configure strict HTTP security headers (Strict-Transport-Security, X-Frame-Options) to limit token exposure vectors; audit existing logs for exposed refresh tokens and rotate any tokens found in historical logs. Additionally, review OAuth provider callback handlers to ensure all token transport follows RFC 6749 requirements and tokens are never included in URL query parameters.
Same weakness CWE-200 – Information Exposure
View allSame technique Information Disclosure
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-19358
GHSA-g2qj-prgh-4g9r