Every CVE Search/ Get API key

CVE-2026-73302

Budibase: OIDC SSO account takeover: incoming identity linked by email without checking email_verified

9.0 Critical

Budibase is an open-source low-code platform. Prior to 3.39.30, the OIDC flow in packages/backend-core/src/middleware/passport/sso/oidc.ts resolved an email without getEmailVerified or an email_verified requirement, and packages/backend-core/src/middleware/passport/sso/sso.ts then used users.getGlobalUserByEmail as a fallback account-linking key. An attacker who can authenticate through a configured identity provider that asserts a victim email as unverified can have a fresh provider identity merged into the victim Budibase account and inherit the victim roles. This issue is fixed in version 3.39.30.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
Low
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
High
Availability
High

Exploit likelihood

0.43%Up 0.1 points since Aug 14, 2026
90%50%10%1%

What each source reports

CVE List Score used 9.0

Budibase: OIDC SSO account takeover: incoming identity linked by email without checking email_verified

Budibase is an open-source low-code platform. Prior to 3.39.30, the OIDC flow in packages/backend-core/src/middleware/passport/sso/oidc.ts resolved an email without getEmailVerified or an email_verified requirement, and packages/backend-core/src/middleware/passport/sso/sso.ts then used users.getGlobalUserByEmail as a fallback account-linking key. An attacker who can authenticate through a configured identity provider that asserts a victim email as unverified can have a fresh provider identity merged into the victim Budibase account and inherit the victim roles. This issue is fixed in version 3.39.30.

Record
CVE-2026-73302
CVSS 4.0
9.0 CriticalCVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
Weakness
CWE-287
Updated
2026-11-02
EUVDEUVD-2026-58525 9.0

Budibase is an open-source low-code platform. Prior to 3.39.30, the OIDC flow in packages/backend-core/src/middleware/passport/sso/oidc.ts resolved an email without getEmailVerified or an email_verified requirement, and packages/backend-core/src/middleware/passport/sso/sso.ts then used users.getGlobalUserByEmail as a fallback account-linking key. An attacker who can authenticate through a configured identity provider that asserts a victim email as unverified can have a fresh provider identity merged into the victim Budibase account and inherit the victim roles. This issue is fixed in version 3.39.30.

Record
EUVD-2026-58525
CVSS 4.0
9.0 CriticalCVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
Updated
2026-11-02
GitHub AdvisoriesGHSA-hp6v-6jw7-gv2f 9.0

Budibase: OIDC SSO account takeover: incoming identity linked by email without checking email_verified

Summary

Budibase's OIDC SSO login links an incoming SSO identity to an existing Budibase account by email address alone, without ever checking the email_verified claim of the OIDC ID token. Budibase first tries to match the IdP sub; when that misses (any fresh attacker IdP account) it silently falls back to matching by the email claim and merges into the existing account by email, preserving that account's _id and roles. Because the email_verified flag is never read, an attacker who can make a configured/trusted IdP emit a token carrying email = <victim> with email_verified = false is logged into Budibase as the victim, inheriting the victim's roles (including global admin/builder). Per OIDC Core §5.7 the email claim MUST NOT be used as an identity key unless email_verified is true; Budibase effectively delegates all account-linking trust to every configured IdP's email-verification policy while checking nothing itself. Full account takeover of any existing Budibase user, including the instance owner.

Details

The OIDC verify callback extracts the email and never consults email_verified:

  • packages/backend-core/src/middleware/passport/sso/oidc.ts:59 — email: getEmail(profile, jwtClaims).
  • getEmail (oidc.ts:113-135) returns profile._json.email ->jwtClaims.email -> preferred_username. No email_verified check.
  • buildJwtClaims (oidc.ts:99-107) assembles claims from _json.email/emails[0].value — no verification flag is read. grep -r email_verified packages/ -> 0 hits.

The email is then used as the account-linking key:

  • sso.authenticate(...) -> packages/backend-core/src/middleware/passport/sso/sso.ts:
    • :38,44 users.getById(generateGlobalUserID(details.userId)) keyed on the IdP sub; for a fresh attacker IdP account this 404s and is swallowed (:45-54).
    • :57-59 fallback: dbUser = await users.getGlobalUserByEmail(details.email) -> loads the victim's account (victim _id + roles) purely by email (packages/backend-core/src/users/users.ts:100-124, USER_BY_EMAIL view, no binding to the IdP sub).
    • syncUser(...) (sso.ts:80,102-138) spreads ...user, preserving the victim _id/tenantId/roles; only overwrites provider fields.
  • UserDB.save (packages/backend-core/src/users/db.ts:235): because ssoUser._id is the victim's, the _id branch runs (:253), getById(_id) matches the victim (:256), the "Email address cannot be changed" guard (:257-259) does not fire (dbUser.email === email), and the EmailUnavailableError guard (:269-275) is skipped (it only runs in the !dbUser branch). The merge proceeds silently; a session JWT is issued for the victim.

Per OIDC Core §5.7, the email claim MUST NOT be used as an identity key unless email_verified is true. Budibase never reads the flag.

Preconditions (attack requirement — AT:P): the attacker must be able to authenticate through an IdP that the Budibase instance trusts AND get that IdP to assert the victim's email with email_verified = false. This is reachable, not exotic:

  • Self-registration with an unverified email — Keycloak and Authentik ship with "Verify Email" OFF by default; if the trusted IdP allows public sign-up, the attacker registers a new account and simply enters email = <victim> at sign-up. No confirmation email is needed — the IdP stores and asserts it unverified.
  • Self-service profile editing — many IdPs let a logged-in user change their own email without forced re-verification.
  • Attacker-operated / federated IdP or permissive social login — where the attacker controls or influences a trusted provider, or the provider asserts a user-typed (unverified) email. It is not exploitable through a strict corporate IdP that enforces email verification (there email_verified = true and the attacker cannot claim the victim's address) — which is exactly why Budibase must check the flag…
Record
GHSA-hp6v-6jw7-gv2f
CVSS 4.0
9.0 CriticalCVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
Weakness
CWE-287
Updated
2026-11-02
NVD 9.0

Budibase is an open-source low-code platform. Prior to 3.39.30, the OIDC flow in packages/backend-core/src/middleware/passport/sso/oidc.ts resolved an email without getEmailVerified or an email_verified requirement, and packages/backend-core/src/middleware/passport/sso/sso.ts then used users.getGlobalUserByEmail as a fallback account-linking key. An attacker who can authenticate through a configured identity provider that asserts a victim email as unverified can have a fresh provider identity merged into the victim Budibase account and inherit the victim roles. This issue is fixed in version 3.39.30.

Record
CVE-2026-73302
CVSS 4.0
9.0 CriticalCVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Weakness
CWE-287
Updated
2026-11-02
OSV 9.0

Budibase: OIDC SSO account takeover: incoming identity linked by email without checking email_verified

Budibase is an open-source low-code platform. Prior to 3.39.30, the OIDC flow in packages/backend-core/src/middleware/passport/sso/oidc.ts resolved an email without getEmailVerified or an email_verified requirement, and packages/backend-core/src/middleware/passport/sso/sso.ts then used users.getGlobalUserByEmail as a fallback account-linking key. An attacker who can authenticate through a configured identity provider that asserts a victim email as unverified can have a fresh provider identity merged into the victim Budibase account and inherit the victim roles. This issue is fixed in version 3.39.30.

Record
CVE-2026-73302
CVSS 4.0
9.0 CriticalCVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
Weakness
CWE-287
Updated
2026-11-02
OSVGHSA-hp6v-6jw7-gv2f 9.0

Budibase: OIDC SSO account takeover: incoming identity linked by email without checking email_verified

Summary

Budibase's OIDC SSO login links an incoming SSO identity to an existing Budibase account by email address alone, without ever checking the email_verified claim of the OIDC ID token. Budibase first tries to match the IdP sub; when that misses (any fresh attacker IdP account) it silently falls back to matching by the email claim and merges into the existing account by email, preserving that account's _id and roles. Because the email_verified flag is never read, an attacker who can make a configured/trusted IdP emit a token carrying email = <victim> with email_verified = false is logged into Budibase as the victim, inheriting the victim's roles (including global admin/builder). Per OIDC Core §5.7 the email claim MUST NOT be used as an identity key unless email_verified is true; Budibase effectively delegates all account-linking trust to every configured IdP's email-verification policy while checking nothing itself. Full account takeover of any existing Budibase user, including the instance owner.

Details

The OIDC verify callback extracts the email and never consults email_verified:

  • packages/backend-core/src/middleware/passport/sso/oidc.ts:59 — email: getEmail(profile, jwtClaims).
  • getEmail (oidc.ts:113-135) returns profile._json.email ->jwtClaims.email -> preferred_username. No email_verified check.
  • buildJwtClaims (oidc.ts:99-107) assembles claims from _json.email/emails[0].value — no verification flag is read. grep -r email_verified packages/ -> 0 hits.

The email is then used as the account-linking key:

  • sso.authenticate(...) -> packages/backend-core/src/middleware/passport/sso/sso.ts:
    • :38,44 users.getById(generateGlobalUserID(details.userId)) keyed on the IdP sub; for a fresh attacker IdP account this 404s and is swallowed (:45-54).
    • :57-59 fallback: dbUser = await users.getGlobalUserByEmail(details.email) -> loads the victim's account (victim _id + roles) purely by email (packages/backend-core/src/users/users.ts:100-124, USER_BY_EMAIL view, no binding to the IdP sub).
    • syncUser(...) (sso.ts:80,102-138) spreads ...user, preserving the victim _id/tenantId/roles; only overwrites provider fields.
  • UserDB.save (packages/backend-core/src/users/db.ts:235): because ssoUser._id is the victim's, the _id branch runs (:253), getById(_id) matches the victim (:256), the "Email address cannot be changed" guard (:257-259) does not fire (dbUser.email === email), and the EmailUnavailableError guard (:269-275) is skipped (it only runs in the !dbUser branch). The merge proceeds silently; a session JWT is issued for the victim.

Per OIDC Core §5.7, the email claim MUST NOT be used as an identity key unless email_verified is true. Budibase never reads the flag.

Preconditions (attack requirement — AT:P): the attacker must be able to authenticate through an IdP that the Budibase instance trusts AND get that IdP to assert the victim's email with email_verified = false. This is reachable, not exotic:

  • Self-registration with an unverified email — Keycloak and Authentik ship with "Verify Email" OFF by default; if the trusted IdP allows public sign-up, the attacker registers a new account and simply enters email = <victim> at sign-up. No confirmation email is needed — the IdP stores and asserts it unverified.
  • Self-service profile editing — many IdPs let a logged-in user change their own email without forced re-verification.
  • Attacker-operated / federated IdP or permissive social login — where the attacker controls or influences a trusted provider, or the provider asserts a user-typed (unverified) email. It is not exploitable through a strict corporate IdP that enforces email verification (there email_verified = true and the attacker cannot claim the victim's address) — which is exactly why Budibase must check the flag…
Record
GHSA-hp6v-6jw7-gv2f
CVSS 4.0
9.0 CriticalCVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
Weakness
CWE-287
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
@budibase/server
npm
through 3.38.1 None known

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-73302 is a critical vulnerability (CVSS 9.0) in Budibase, published July 24, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.43%, the 37th percentile. No source names a fixed version.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open