Nhost Account Takeover via OAuth Email Verification Bypass
Nhost is vulnerable to account takeover due to improper OAuth email verification in Discord, Bitbucket, AzureAD, and EntraID providers, allowing attackers to merge an unverified OAuth identity into a victim's account.
Nhost is vulnerable to account takeover due to improper OAuth email verification. The vulnerability stems from Nhost automatically linking incoming OAuth identities to existing Nhost accounts when email addresses match, without properly verifying the email with the OAuth provider. Several provider adapters, including Discord, Bitbucket, AzureAD, and EntraID, fail to correctly populate the profile.EmailVerified field. This allows an attacker to present an email they don't own to Nhost, have the OAuth identity merged into the victim's account, and gain a fully authenticated session. The vulnerable code is located in services/auth/go/controller/sign_in_id_token.go. Affected Nhost versions are prior to 0.0.0-20260417112436-ec8dab3f2cf4.
Attack Chain
- The attacker identifies a target Nhost application that utilizes a vulnerable OAuth provider (Discord, Bitbucket, AzureAD, or EntraID).
- The attacker creates an account on the chosen OAuth provider.
- The attacker modifies their email address on the OAuth provider to match the email address of the victim's Nhost account. In the case of Discord, the attacker changes the email but skips the verification step.
- The attacker initiates the "Sign in with [OAuth Provider]" flow on the target Nhost application.
- Nhost's backend fetches the attacker's profile from the OAuth provider. Due to the vulnerability, Nhost incorrectly trusts the 'verified' status, even if the email is unverified.
- Nhost locates the victim's account based on the matching email address.
- Nhost links the attacker's OAuth provider identity to the victim's account in the database using the
InsertUserProviderfunction. - Nhost generates a new session for the victim's account and provides it to the attacker, granting the attacker full access to the victim's account.
Impact
Successful exploitation allows for full account takeover of any existing Nhost user, without requiring any interaction from the victim. The attacker can then change the account email, disable other login methods, and permanently lock out the legitimate owner. This is particularly critical in applications with admin or privileged accounts, potentially leading to significant data breaches or unauthorized access to sensitive systems. The vulnerability affects Nhost versions prior to 0.0.0-20260417112436-ec8dab3f2cf4.
Recommendation
- Upgrade Nhost to a version containing the fix for this vulnerability (>= 0.0.0-20260417112436-ec8dab3f2cf4).
- Implement a controller-level guard that enforces email verification regardless of the adapter's reported
EmailVerifiedstatus, as described in the "Defense-in-Depth Gap" section. This mitigates the risk of future vulnerabilities due to changes in OAuth provider APIs. - For Discord, apply the fix described in the advisory, adding the
Verifiedfield to thediscordUserProfilestruct and utilizing it in theEmailVerifiedassignment within theproviders/discord.gofile. - For Bitbucket, remove the fallback to unconfirmed emails as described in the advisory, preventing the adapter from using unverified emails in
providers/bitbucket.go. - For AzureAD and EntraID, avoid falling back to
preferred_usernameor UPN for account-linking email, as these fields do not prove email ownership, as documented in the advisory.
Detection coverage 2
Detect Discord OAuth User Profile Request
infoDetects requests to the Discord API endpoint for retrieving user profile information, potentially indicating an OAuth flow. This can be used to monitor for unusual or suspicious OAuth activity.
Detect Bitbucket Email API Request
infoDetects network connections to Bitbucket's email API endpoint which reveals confirmed and unconfirmed emails tied to a Bitbucket user. This can be used to discover suspicious OAuth or account enumeration activity.
Detection queries are available on the platform. Get full rules →