# Authorizer: Zero-click account takeover via OAuth identity linking to unverified email accounts

Authorizer's OAuth callback links provider identities to existing accounts by email without checking the account's email was verified, letting an attacker who pre-registered the victim's email keep password access after the victim's OAuth login.

- Payout: Research
- Severity: high
- Program: Authorizer
- Found by: kodareef5
- Disclosed: 2026-08-14
- CVE: CVE-2026-35511
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-29rf-f4vv-pvq6
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-29rf-f4vv-pvq6
- Tags: area:web domain:web impact:ato kind:research platform:ghsa sev:high tech:go tech:oauth technique:chained technique:source-review vuln:access-control vuln:account-takeover vuln:auth-bypass

**Target:** OAuth callback handler in Authorizer auth server (Go)
**Root cause:** The OAuth callback looks up an existing user by email and merges the OAuth identity into it without checking that the existing account's email was verified by its owner, and without invalidating the pre-existing password. It even auto-sets EmailVerifiedAt on the unverified account.
**Steps:**
1. Attacker registers `victim@company.com` with a known password via basic auth and never clicks the verification link, leaving `EmailVerifiedAt = nil`.
2. Victim later logs in normally via Google OAuth.
3. Callback at `oauth_callback.go:125` calls `h.StorageProvider.GetUserByEmail(ctx, refs.StringValue(user.Email))` and finds the attacker's account.
4. Line 164 replaces the OAuth user with the existing user (`user = existingUser`); lines 173-176 append `google` to `SignupMethods`.
5. Lines 179-181 set `user.EmailVerifiedAt` to now because it was nil; line 219 persists via `UpdateUser`.
6. Attacker logs in with `victim@company.com` and the original password, now sharing the account with the victim's OAuth session.
**How found:** Code review of the OAuth callback's account-linking branch: noticed the existing user is fetched by email and merged without any check on `EmailVerifiedAt`, and that the auto-verify block at lines 179-181 silently promotes an unverified account.
**Exploitation:** Pre-stage an unverified account with the victim's email and a chosen password, wait for the victim to perform a normal OAuth login, then authenticate with the staged password to access the victim's account and all data created after linking. Access persists even if the victim revokes Authorizer's OAuth grant.
**Escalation:** Works across every configured OAuth provider (Google, GitHub, Facebook, Apple, LinkedIn, Twitter, Discord, Twitch, Roblox, Microsoft), so any OAuth-enabled deployment is exposed.
**Insight:** In account-linking flows, the trust boundary is the pre-existing account, not the incoming IdP assertion: if the local account's email was never verified, linking an IdP identity to it hands the IdP-verified victim's session to whoever staged the account. Also check whether the linking path clears existing credentials.

