Listen to this Post
How the CVE Works:
The vulnerability resides in Nhost’s OAuth identity linking logic. When a user signs in with a provider (Discord, Bitbucket, AzureAD, EntraID), Nhost automatically links the provider identity to an existing account if the email addresses match – without verifying that the email is actually owned by the person. The controller function `providerFlowSignIn()` in `sign_in_id_token.go` calls `InsertUserProvider` and issues a session based solely on `profile.EmailVerified` returned by each provider adapter. Several adapters populate this field incorrectly: Discord’s struct omits the `verified` field from its API, so it sets `EmailVerified = (email != “”)` – always true even for unconfirmed emails. Bitbucket queries `/user/emails` but falls back to an unconfirmed email if no confirmed one exists, then marks it verified. AzureAD and EntraID derive email from `preferred_username` or `UPN` (non-ownership fields) and again set EmailVerified = true. An attacker can change their Discord email to the victim’s address without verifying it, then sign in via Discord. Nhost sees the unverified email, treats it as verified due to the missing field, links the attacker’s provider ID to the victim’s account, and issues a full authenticated session to the attacker. The victim receives no notification. The same pattern applies to Bitbucket (add unconfirmed email) and Microsoft providers (spoof UPN).
dailycve form:
Platform: Nhost Auth
Version: Prior fix
Vulnerability: OAuth email trust
Severity: Critical
date: 2026-04-18
Prediction: Patch by 2026-05-18
What Undercode Say:
Check Discord API response for verified field (attacker's unverified email)
curl -H "Authorization: Bot YOUR_TOKEN" https://discord.com/api/v9/users/@me
Expected: {"email": "[email protected]", "verified": false}
Simulate Nhost's missing field in Go (vulnerable struct)
cat <<EOF > discord_bug.go
type discordUserProfile struct {
Email string `json:"email"`
// Missing: Verified bool
}
EOF
Verify Bitbucket unconfirmed email fallback
curl -u username:app_password https://api.bitbucket.org/2.0/user/emails
Look for "is_confirmed": false entries
Test AzureAD UPN spoof - set UPN to victim's email in Azure tenant
Then sign in via Nhost; controller accepts unverified email
Exploit:
- Attacker creates Discord account, changes email to [email protected], skips verification.
- Attacker signs into Nhost app using “Sign in with Discord”.
- Nhost fetches profile: [email protected], verified field dropped → EmailVerified=true.
- Nhost finds victim’s existing account by email match, links attacker’s Discord ID.
- Nhost issues session cookie for victim’s account to attacker.
Protection from this CVE
- Add
Verified booljson:”verified”“ to Discord struct and mapEmailVerified: userProfile.Verified. - Remove Bitbucket fallback to unconfirmed email; require
IsConfirmed == true. - In AzureAD/EntraID, do not use preferred_username or UPN for email; rely only on `email_verified` claim from OIDC id_token.
- Add controller-level guard: reject linking if `!profile.EmailVerified` regardless of provider.
- Enable email confirmation requirement in Nhost settings and audit all provider adapters.
Impact
- Full account takeover of any Nhost user with zero victim interaction.
- Attacker can change account email, disable other logins, lock out owner permanently.
- Critical in apps with admin/privileged accounts; no logs of the merge operation.
🎯Let’s Practice Exploiting & Learn Patching For Free:
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

