### 漏洞概述 **漏洞名称**: Account Takeover via OAuth Email Verification Bypass **漏洞描述**: Nhost 在自动将 OAuth 身份与现有账户关联时,仅依赖邮箱地址匹配,而未验证邮箱是否经过 OAuth 提供商确认。部分 OAuth 提供商(如 Discord、Bitbucket、AzureAD、EntraID)未能正确填充 `verified` 字段,导致攻击者可以冒充受害者账户。 **根本原因**: 控制器在 `providerFlowSignIn` 中直接信任 `provider.EmailVerified`,而未检查该字段是否由 OAuth 提供商正确设置。 ### 影响范围 **受影响版本**: - `<0.49.1` **修复版本**: - `0.49.1` **影响**: - 攻击者可接管任何现有 Nhost 用户账户。 - 无需与受害者交互。 - 攻击者可更改账户邮箱、禁用其他登录方法,永久锁定合法用户。 - 严重性从高危升级为严重,特别是在管理员或特权账户中。 ### 修复方案 **修复代码**: 1. **GitHub 提供商 (`providers/github.go`)**: ```go selected := selectEmails(emails) // only selects verified: true entries return oidc.Profile{ Email: selected.Email, EmailVerified: selected.Verified, // real boolean from GitHub API } ``` 2. **Discord 提供商 (`providers/discord.go`)**: ```go type discordUserProfile struct { ID string `json:"id"` Username string `json:"username"` Discriminator string `json:"discriminator"` Email string `json:"email"` Verified bool `json:"verified"` // add this Locale string `json:"locale"` Avatar string `json:"avatar"` } return oidc.Profile{ Email: userProfile.Email, EmailVerified: userProfile.Verified, // use it } ``` 3. **Bitbucket 提供商 (`providers/bitbucket.go`)**: ```go if primaryEmail == "" { // Remove the fallback entirely no confirmed email means no sign-in return oidc.Profile{}, ErrNoConfirmedBitbucketEmail } ``` 4. **AzureAD 提供商 (`providers/azuread.go`)**: ```go // Do not fall back to preferred_username or UPN for account-linking email. Only use a field that Azure AD explicitly certifies as a verified external email (or use the OIDC id_token with the email_verified claim from Azure's v2 endpoint). ``` 5. **EntraID 提供商 (`providers/entraid.go`)**: ```go type entraidUser struct { Sub string `json:"sub"` GivenName string `json:"givenname"` FamilyName string `json:"familyname"` Email string `json:"email"` EmailVerified bool `json:"email_verified"` // MISSING: EmailVerified bool `json:"email_verified"` } return oidc.Profile{ Email: userProfile.Email, EmailVerified: userProfile.Email != "", // unconditional } ``` **修复补丁**: - 已修复在 #4162 **CVE ID**: - CVE-2026-41574 **弱点**: - Weakness CWE-287 **信用**: - skovett Reporter