CVE-2026-62367: Vikunja: OIDC email-fallback account linking ignores email_verified, enabling local-account takeover
Summary
With the per-provider OIDC emailfallback option enabled, Vikunja links an SSO login to a pre-existing local (username+password) account using only the email claim — no emailverified (or Microsoft xmsedov) check and no password check, on the unauthenticated callback. An attacker who can make the configured issuer emit a token bearing a victim's email logs in as that victim with a full session and no victim interaction (the nOAuth / Grafana CVE-2023-3128 class). The 2.3.0 fix for GHSA-8jvc-mcx6-r4cg added a TOTP gate, not an emailverified gate, so users without TOTP remain exposed.
Details
References are pkg/modules/auth/openid/openid.go at HEAD. Identity is first resolved on the immutable (issuer, subject) pair (openid.go:428). On a subject miss with emailfallback on, fallbackSearchUsers adds an email-only lookup against local accounts:
go // openid.go:413 searches = append(searches, &user.User{Issuer: user.IssuerLocal, Email: cl.Email})
getUser resolves this via s.Get(), which ANDs non-zero fields -> WHERE issuer='local' AND email=?. Local users always have Issuer="local" (usercreate.go:38), so the lookup matches any local account by email alone; getOrCreateUser returns it and the caller mints a session — the password is never read. The claims struct has no emailverified field (openid.go:80) and getClaims never consults one; a repo-wide grep for emailverified/xmsedov returns nothing. The code already warns about this at openid.go:388 ("Discouraged for untrusted providers where someone can set email without verification") — but enforces nothing.
Impact
Unauthenticated takeover of any existing local account (read/write/delete its projects, tasks, attachments, shares), bypassing the password. Scope notes: only issuer='local' accounts are matched (not pure-SSO users); the attacker's sub is not bound to the victim record, but the attack is repeatable; TOTP users are protected by the 2.3.0 enforceTOTPIfRequired gate (openid.go:250), non-TOTP users are not.
Preconditions
1. Admin enabled emailfallback: true (defaults false — a default install is unaffected). 2. The configured issuer lets the attacker assert the victim's unverified email: a self-service IdP (Keycloak/Authentik/Auth0/Dex with editable email), a mixed federation, or a multi-tenant Entra /common app. iss/aud are pinned, but the attacker controls email, not the issuer. 3. The victim has a local account.
Not reachable against a single-tenant IdP that verifies email and disallows self-set addresses.
Recommended Fix
Add emailverified to the claims struct and require it true on the email-fallback branch before linking to a local account; reject when absent/false. For Entra also require xmsedov and pin multi-tenant configs to an allowed-tenant list. Fail closed on an email collision not backed by a verified email from a trusted single-tenant issuer rather than silently logging the caller in.
Other sources
Vikunja is an open-source self-hosted task management platform. In versions 1.0.0 through 2.3.0, when an administrator enables the per-provider emailfallback option on an OpenID Connect provider, Vikunja links an SSO login to a pre-existing local (username+password) account using only the email claim from the IdP. The fallback never checks an emailverified (or Microsoft xmsedov) signal and never requires the matched account's password. An attacker who can obtain a token from the configured issuer carrying a victim's email logs in as that victim with a full session, with no consent or interaction from the victim. Version 2.4.0 fixes the issue.
— MITRE
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
go/code.vikunja.io/apito a version that resolves this vulnerability.Fixed in 2.4.0 - Upgrade
Upgrade
Vikunjato a version that resolves this vulnerability.Fixed in 2.4.0