CVE-2026-91982: Vikunja TOTP Secret Is Readable After Vulnerability
MODERATECVE-2026-91982 is a MODERATE totp secret is readable after vulnerability (CWE-312: Cleartext Storage of Sensitive Information) affecting Vikunja libraries in the Go ecosystem. The issue involves totp secret is readable after enrollment, no step-up auth. Remediation is available by upgrading affected packages to version 2.6.0.
CVE-2026-91982 at a Glance
How to Fix CVE-2026-91982
To remediate this vulnerability, upgrade all affected Vikunja dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
Upgrade code.vikunja.io/api to 2.6.0
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
inspect dependencies for code.vikunja.io/api
How to Check if You Are Affected
To determine whether your application is affected by CVE-2026-91982, inspect your project dependencies for Vikunja:
inspect dependencies for code.vikunja.io/api
Analyze the terminal output to locate any version of Vikunja in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 2.6.0), your application is affected.
Note: Verify declared build manifests and deployed runtime container environments.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-312: Cleartext Storage of Sensitive Information, where the product stores sensitive information in cleartext within a resource that might be accessible to another control sphere. In Vikunja, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-91982 Affected Vikunja Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
code.vikunja.io/api
|
Go |
< 2.6.0
|
2.6.0
|
References
Frequently Asked Questions
What is CVE-2026-91982?
Which Vikunja versions are affected?
What version fixes CVE-2026-91982?
Is code.vikunja.io/api affected?
What CWE is associated with CVE-2026-91982?
How can I check Go dependencies for CVE-2026-91982?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-88f6-4rjv-x774",
"modified" : "2026-10-09T20:51:17Z",
"published" : "2026-10-09T20:51:17Z",
"aliases" : [ "CVE-2026-91982" ],
"summary" : "Vikunja: TOTP secret is readable after enrollment, no step-up auth",
"details" : "### Summary\nOnce a user has TOTP enabled, the API still hands back the raw shared secret to anyone holding that account's access token. Reading it doesn't ask for the password, even though disabling TOTP does. So a stolen token, an XSS, or a browser left open is enough to copy the second factor into your own authenticator and keep generating valid codes indefinitely.\n\n### Details\n`GET /api/v1/user/settings/totp` returns the full TOTP object, including the secret field and the otpauth:// provisioning URL. `GET /api/v1/user/settings/totp/qrcode` renders the same secret as a QR image. Neither requires re-authentication, the access token alone is enough.\n\nThis is inconsistent with the rest of the flow: `POST /api/v1/user/settings/totp/disable` calls CheckUserPassword before it will turn TOTP off. So the destructive action is gated behind the password, but reading out the secret that backs the second factor isn't. There's also no reason for the secret to be readable at all once enrollment is finished, the client only needs it during setup.\n\nThe fix is to stop returning secret/url/the QR code once enabled is true (only expose them during the enrollment window). Requiring the password on the read, like disable already does, would also be reasonable.\n\n### PoC\nThe attacker needs the victim's access token, from an XSS, a leaked/stolen token, or an unlocked session. TOTP must already be enabled on the account.\n\n1. With the victim's bearer token, call:\n```\nGET /api/v1/user/settings/totp\nAuthorization: Bearer <victim_token>\n```\nThe response contains the shared secret and the otpauth:// URL:\n```\n{\"secret\": \"<base32 secret>\", \"enabled\": true, \"url\": \"otpauth://totp/...\"}\n```\n2. Paste that secret (or scan `/api/v1/user/settings/totp/qrcode`) into any authenticator app.\n3. It now produces the same 6-digit codes as the victim's device. Nothing is logged and the victim gets no notification.\n\n### Impact\nThis defeats the purpose of the second factor. 2FA is supposed to survive exactly this situation, a compromised password or a hijacked session, but a single read of the account's own settings hands over the shared secret with no step-up check and no trace. Combined with a known or later-recovered password, it's a durable account takeover that TOTP was meant to prevent.",
"severity" : [ {
"type" : "CVSS_V4",
"score" : "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "Go",
"name" : "code.vikunja.io/api"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "2.6.0"
} ]
} ],
"database_specific" : {
"last_known_affected_version_range" : "<= 2.5.0"
}
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/go-vikunja/vikunja/security/advisories/GHSA-88f6-4rjv-x774"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-91982"
}, {
"type" : "WEB",
"url" : "https://github.com/go-vikunja/vikunja/pull/3688"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/go-vikunja/vikunja"
}, {
"type" : "WEB",
"url" : "https://github.com/go-vikunja/vikunja/releases/tag/v2.6.0"
}, {
"type" : "WEB",
"url" : "https://www.vulncheck.com/advisories/vikunja-before-2.6.0-totp-secret-disclosure-via-api"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-312", "CWE-522" ],
"severity" : "MODERATE",
"github_reviewed" : true,
"github_reviewed_at" : "2026-10-09T20:51:17Z",
"nvd_published_at" : null
}
}