Skip to content

← Public intelligence

Go package

code.vikunja.io/api

Open actionable advisories and recorded vendor fixes. This public package view has no inventory attached and cannot establish whether your deployment is affected. A vendor fix never resolves your finding; verify your installed version and the source guidance.

Open advisories

53 actionable advisories, newest first. Withdrawn advisories and news are excluded. Coverage is partial.

  1. Medium, CVSS 6.9GoAmendedPublished

    Vikunja: Write-level project members can delete admin-tier link shares through an unloaded permission check

    CVE-2026-111921 · GHSA-fmmf-xq98-g327

    Affected
    • Go code.vikunja.io/api >= 0.13.0, < 2.7.0
    Fixed in
    2.7.0· Vendor fix available
    Issue
    A project member with Write permission can delete an admin-tier link share on that project. The deletion authorization check reads the permission from an object populated only with URL IDs, rather than from the stored share. Its zero value is Read, so the check falls through to project Write permission instead of requiring Admin. Details Affected endpoints: - `DELETE /api/v1/projects/{project}/shares/{share}` - `DELETE /api/v2/projects/{project}/shares/{share}` Older v1 releases used `/lists/{list}/shares/{share}` before lists were renamed to projects. In `pkg/routes/api/v2/link_sharing.go:156`, the delete handler passes `&models.LinkSharing{ID: in.ID, ProjectID: in.ProjectID}` to `handler.DoDelete`. The v1 generic handler likewise binds the URL IDs without loading the stored share. `pkg/web/handler/core.go:185` calls `CanDelete` before `Delete`. `LinkSharing.CanDelete` delegates to `canDoLinkShare` in `pkg/models/link_sharing_permissions.go`. That helper loads the…

    Recommended action: Upgrade to 2.7.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  2. Medium, CVSS 5.4GoAmendedPublished

    Vikunja: Explicit lower-permission share on a sub-project is silently overridden by an inherited parent permission (broken access control / privilege-management regression in v2.6.0)

    CVE-2026-111920 · GHSA-pjr3-86v4-5p7w

    Affected
    • Go code.vikunja.io/api >= 2.6.0, < 2.7.0
    Fixed in
    2.7.0· Vendor fix available
    Issue
    Summary In Vikunja v2.6.0 the project-permission engine resolves a user's effective permission on a project as the MAX over the entire reachable project subtree. As a result, when a user has been granted a higher permission on a parent project and the owner *explicitly* shares a child project with that same user at a lower permission (an intended down-restriction), the explicit lower grant is silently ignored and the user receives the higher, inherited permission on the child. A user who was deliberately restricted to read-only on a sensitive sub-project can therefore modify it, delete it, and re-share it (including granting other users admin) - none of which the owner intended. This is a behavior regression from v2.5.0, whose engine used "nearest-ancestor-grant-wins" semantics that honored the explicit child grant. Details Effective permissions are computed by a single recursive CTE in `pkg/models/project_access.go`…

    Recommended action: Upgrade to 2.7.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  3. Medium, CVSS 5.4GoAmendedPublished

    Vikunja: Saved filter creation with an empty filter string recalculates task positions across all tenants

    CVE-2026-111918 · GHSA-fprf-r6rv-xg99

    Affected
    • Go code.vikunja.io/api >= 1.0.0-rc0, < 2.7.0
    Fixed in
    2.7.0· Vendor fix available
    Issue
    In Vikunja v2.6.0 the task position recalculation that runs when a saved filter view is created fails open when the requesting user has no accessible projects. Instead of aborting, the search that feeds the recalculation loses its project scope entirely and returns every task in the instance. The server then writes one `task_positions` row per task per view (four views per filter) into views owned by the requesting user, including rows that reference tasks of other tenants the user can never see. Any authenticated user can trigger this. The impact is a cross-tenant integrity violation, a single-request write amplification primitive that scales with instance size, and a violation of the invariant stated in the fix for GHSA-w39f-h553-h2mx that position writes are scoped by project read access. Details Vikunja computes kanban and list ordering in a shared `task_positions` table keyed by `(task_id, project_view_id)`. When a saved filter is created, `SavedFilter.Create`…

    Recommended action: Upgrade to 2.7.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  4. Medium, CVSS 6.5GoAmendedPublished

    Vikunja: WebSocket authentication ignores server-side session state, so revoked sessions keep receiving live pushes

    CVE-2026-111917 · GHSA-4hv6-xc92-j86g

    Affected
    • Go code.vikunja.io/api >= 2.3.0, < 2.7.0
    Fixed in
    2.7.0· Vendor fix available
    Issue
    Vikunja v2.6.0 introduced server-side sessions with revocation semantics: `DELETE /api/v2/user/sessions/{id}` documents "Revokes a specific session by its UUID", and enabling TOTP calls `DeleteAllUserSessions` to invalidate all sessions. The WebSocket endpoint accepts any cryptographically valid user JWT without ever resolving its `sid` (session id) claim against the sessions table. A connection authenticated before revocation stays authenticated and continues to receive live pushes indefinitely, and even brand-new WebSocket connections are accepted with a token whose session was deleted. The revocation feature therefore does not cover the WebSocket boundary at all. Details User access JWTs carry a session reference: `NewUserJWTAuthtoken` (`pkg/modules/auth/auth.go:188`) sets `claims["sid"] = sessionID`, and the API login-session documentation describes the claim as tying the JWT to a server-side session. On the HTTP side nothing consumes the claim per request either…

    Recommended action: Upgrade to 2.7.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  5. Medium, CVSS 5.3GoAmendedPublished

    Vikunja: Assignee email addresses disclosed to read-only project members via the task assignees endpoint

    GHSA-8wvg-r2j4-3737

    Affected
    • Go code.vikunja.io/api <= 2.5.0
    Fixed in
    2.6.0· Vendor fix available
    Issue
    TaskAssginee.ReadAll returns assignee user objects without blanking the Email field, disclosing assignee email addresses to any read-only project member. Every sibling path that returns user objects obfuscates the email; this one does not. Details pkg/models/taskassignees.go (~lines 306-344) does Select("users.") and returns the result directly. User.Email is json:"email,omitempty", so a non-empty value always serializes. The endpoint gates on task.CanRead, so a read-only member passes. Sibling paths blank the field: pkg/models/tasks.go:530, pkg/models/projectusers.go:216, pkg/models/teams.go:177, pkg/models/labeltask.go:312, pkg/models/taskattachment.go:511. The omission here reads as an oversight, not a decision. The same file's getRawTaskAssigneesForTasks (~line 56) also selects users. but is safe because its only caller (addAssigneesToTasks) blanks the email afterwards. PoC (verified at runtime against v2.5.0, v1 and v2) Same leak on GET /api/v2/tasks/{id}/assignees…

    Recommended action: Upgrade to 2.6.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  6. Medium, CVSS 6.0GoAmendedPublished

    Vikunja: Cross-project task disclosure through subtask expansion

    GHSA-3hc7-r24j-rpwc

    Affected
    • Go code.vikunja.io/api <= 2.5.0
    Fixed in
    2.6.0· Vendor fix available
    Issue
    Vikunja lets a task in one project have a subtask that lives in a different project. When listing a project's tasks, an option pulls in those subtasks (?expand%5B%5D=subtasks). The main listing is correctly filtered to the projects the caller can access, but the subtask expansion is not: it returns the linked subtasks regardless of whether the caller has any access to the project they belong to. So a member with read-only access to one project can read the full content of tasks in other, private projects, any task that is a (recursive) subtask of a task the member is allowed to see. Details Subtasks can cross project boundaries; a task in an accessible project can be linked as the parent of a subtask that lives in a private project. Creating that link requires access to both tasks, so the link itself is set up legitimately by someone who has it. The problem is what happens afterwards, on read. When a task list is requested with subtask expansion, the server takes the tasks…

    Recommended action: Upgrade to 2.6.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  7. Medium, CVSS 6.3GoAmendedPublished

    Vikunja: CalDAV relation creation bypasses TaskRelation.CanCreate, allowing an unauthorized write into any task by known UID

    GHSA-g38j-7v97-x298

    Affected
    • Go code.vikunja.io/api <= 2.5.0
    Fixed in
    2.6.0· Vendor fix available
    Issue
    Creating a task relation over CalDAV does not run the TaskRelation.CanCreate permission check that the REST API enforces. An attacker can attach a relation to any task whose UID they know, including tasks in projects they have no access to. The identical operation over REST is correctly refused with 403. Details persistRelations (pkg/routes/caldav/listStorageProvider.go, ~line 986) resolves the related task with an unscoped UID lookup (models.GetTaskSimpleByUUID) and calls rel.Create(s, a) directly, with no CanCreate check. pkg/caldav/parsing.go maps RELATED-TO;RELTYPE=CHILD to RelationKindSubtask. Because the CalDAV path never invokes the model's permission method, an authenticated user can create a subtask/parent relation between a task they own and an arbitrary victim task identified only by its UID. Task UIDs are json:"-" (never exposed over REST) but are exposed over CalDAV to anyone who has ever had read access to the containing project. Revoking that access does not…

    Recommended action: Upgrade to 2.6.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  8. High, CVSS 7.1GoAmendedPublished

    Vikunja: Planka migration retains an unbounded aggregate of attacker-served attachments and can OOM the API

    CVE-2026-91970 · GHSA-wq92-8x3r-fm38

    Affected
    • Go code.vikunja.io/api >= 2.5.0, < 2.6.0
    Fixed in
    2.6.0· Vendor fix available
    Issue
    Planka migration retains an unbounded aggregate of attacker-served attachments and can OOM the API Summary The always-registered Planka migration lets any ordinary user select a Planka server. Although Vikunja caps each JSON response, pagination loop, and attachment independently, it has no aggregate job budget. The conversion stage downloads every advertised non-link attachment and keeps every byte slice live until the complete hierarchy is inserted. A public attacker server can therefore drive memory beyond any finite service allocation. The final Docker run preserved default SSRF policy and OOM-killed the healthy API after five individually valid 20 MiB attachment responses. Impact and affected scope - Type: Resource Exhaustion Dos - Affected component: POST /api/v2/migration/planka/migrate; Asynchronous migration.requested worker for the Planka migrator - Preconditions: A low-privilege Vikunja user supplies an attacker-operated public Planka URL and token. That server controls…

    Recommended action: Upgrade to 2.6.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  9. High, CVSS 7.1GoAmendedPublished

    Vikunja: Unbounded CSV row cardinality permits API process termination

    CVE-2026-91969 · GHSA-pqf9-h8g4-8gmh

    Affected
    • Go code.vikunja.io/api >= 2.5.0, <= 2.5.0
    Fixed in
    2.6.0· Vendor fix available
    Issue
    Unbounded CSV row cardinality permits API process termination Summary The authenticated v2 CSV migration route caps upload bytes but not parsed row cardinality. It reads every record into a [][]string and then materializes a full task object for every row before insertion. Two million one-cell rows fit in a roughly 4 MB multipart request yet exhaust a 512 MiB API process. Impact and affected scope - Type: Resource Exhaustion Csv Import - Affected component: POST /api/v2/migration/csv/migrate - Preconditions: An ordinary authenticated user supplies a multipart CSV containing a very large number of tiny records plus a valid mapping configuration. - Verified revision: 349cd5adbcc831ef08b08e6c9c6d627603c39606 on 28 August 2026 - Affected release range: = 2.5.0; broader historical range not established and maintainer confirmation requested A low-privileged remote user can terminate the API process and deny service to all users with a request far below the configured upload-byte limit.…

    Recommended action: Upgrade to 2.6.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  10. High, CVSS 7.1GoAmendedPublished

    Vikunja: Unbounded nested task-filter recursion permits API process termination

    CVE-2026-91968 · GHSA-xxc3-xpmc-vmvr

    Affected
    • Go code.vikunja.io/api >= 2.5.0, <= 2.5.0
    Fixed in
    2.6.0· Vendor fix available
    Issue
    Unbounded nested task-filter recursion permits API process termination Summary Authenticated task-list routes accept a filter expression without a length or nesting-depth bound, preprocess it, parse it recursively through fexpr, and recursively convert the resulting expression tree. A syntactically valid deeply nested expression well below the HTTP request-size ceiling exhausts memory and kills the API process. Impact and affected scope - Type: Resource Exhaustion Recursive Parser - Affected component: GET /api/v2/projects/{project}/tasks?filter=<nested expression; Other authenticated task-collection entrypoints that share getTaskFiltersFromFilterString - Preconditions: A low-privileged authenticated user supplies thousands of balanced parentheses around a valid task predicate in the filter query parameter. - Verified revision: 349cd5adbcc831ef08b08e6c9c6d627603c39606 on 28 August 2026 - Affected release range: = 2.5.0; broader historical range not established and maintainer…

    Recommended action: Upgrade to 2.6.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  11. High, CVSS 7.1GoAmendedPublished

    Vikunja: Denial of service via decompression bomb in the data import

    CVE-2026-91979 · GHSA-w7jp-mf2v-8342

    Affected
    • Go code.vikunja.io/api <= 2.5.0
    Fixed in
    2.6.0· Vendor fix available
    Issue
    Vikunja lets you export your data as a zip and import it back. The import doesn't limit how large the archive expands to, how many files it contains, or how much storage one user can consume, and it appears to hold the whole archive in memory while processing it. Because the archive is compressed, a ~20 MB upload made of highly compressible content expands to tens of gigabytes once imported. A single crafted upload is enough to exhaust the server's memory or fill its disk and knock the whole instance offline. It can be repeated or run in parallel, since nothing stops a user from starting several imports at once. Details The import accepts an archive in the same layout the built-in export produces: a manifest describing projects and tasks, plus the attachment files those tasks reference. Each individual file inside the archive is size-checked, but there's no ceiling on the total uncompressed size or on the number of files, and there's no per-user storage quota anywhere. On top…

    Recommended action: Upgrade to 2.6.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  12. Medium, CVSS 5.3GoAmendedPublished

    Vikunja: Link-share token can enumerate users through the v2 API

    CVE-2026-91981 · GHSA-vfxw-3x8p-2vjr

    Affected
    • Go code.vikunja.io/api <= 2.5.0
    Fixed in
    2.6.0· Vendor fix available
    Issue
    A link-share token, the credential you hand out to let someone view a shared project, can call the v2 user-search endpoints, which it was never meant to reach. The v1 versions of the same endpoints correctly reject link-share tokens; the v2 versions don't. As a result, anyone with a share link can list every member of the shared project (and its parent projects), and can test whether any username exists anywhere on the instance. Details Two endpoints are affected: GET /api/v2/projects/{id}/users/search only checks project.CanRead, which a link share satisfies on its own project. With no parameter it returns the full user list, walking up the parent-project chain. GET /api/v2/users?q=<name is a global search. It needs a query term, but any term works as an existence oracle: a hit confirms the username exists somewhere on the instance and returns the display name. Emails are correctly stripped from these responses, so the exposure is limited to identities (usernames and display…

    Recommended action: Upgrade to 2.6.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  13. Medium, CVSS 5.3GoAmendedPublished

    Vikunja: Any user can enumerate every team and its members by attaching arbitrary teams to a throwaway project

    CVE-2026-91980 · GHSA-39p5-2wrr-xh29

    Affected
    • Go code.vikunja.io/api <= 2.5.0
    Fixed in
    2.6.0· Vendor fix available
    Issue
    When you share a project with a team, the API lets you attach any team on the instance, including teams you have nothing to do with, as long as you're an admin of the project. Listing a project's teams then returns each team's full member roster. So any logged-in user can spin up a throwaway project, attach team IDs one by one, and read back the name, description, and complete member list of every team on the instance. Normally you can only see teams you belong to; this path ignores that. Details Sharing a project with a team is a two-step flow: you PUT a team to the project, then you GET the project's teams to see them. The share endpoint only enforces that you're an admin of the target project, it doesn't care whether the team you're referencing is one you're allowed to see. Any existing team ID is accepted. The listing endpoint is even more permissive: read access to the project is enough, which you obviously have on a project you created. And its response isn't just a…

    Recommended action: Upgrade to 2.6.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  14. High, CVSS 7.1GoAmendedPublished

    Vikunja: Unbounded image decode on avatar and project-background uploads enables decode/resize amplification

    CVE-2026-91971 · GHSA-4vh2-39rq-rq8j

    Affected
    • Go code.vikunja.io/api <= 2.5.0
    Fixed in
    2.6.0· Vendor fix available
    Issue
    The 50-megapixel decode guard exists only on the task-attachment preview path. Avatar and project-background uploads decode uploaded images with no pixel cap. Worse, the avatar resize fixes the output height at 1024 and derives the width from the aspect ratio, so a tiny extreme-aspect-ratio PNG expands to an enormous output image — an input-side pixel cap would not catch it. Details The only maxPixels check (50MP) is in TaskAttachment.GetPreview (pkg/models/taskattachment.go ~lines 332-338). No such check guards: - avatar upload: pkg/modules/avatar/upload/upload.go (~lines 82, 137, 141) - project background: pkg/modules/background/handler/background.go (~lines 174, 269, 289) imaging.Resize(img, 0, 1024, imaging.Lanczos) (upload.go ~line 141) fixes height=1024 and derives width from the aspect ratio: a 20000x10 input yields a ~2,048,000 x 1024 output (~2.1 billion pixels), so a few-hundred-byte file drives huge CPU and memory. PoC (verified at runtime against v2.5.0) Contrast…

    Recommended action: Upgrade to 2.6.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  15. UnratedGoAmendedPublished

    Vikunja: CalDAV and feeds BasicAuth endpoints have no rate limit, bypassing the anti-brute-force floor on account passwords

    CVE-2026-91973 · GHSA-m469-88xx-8rx2

    Affected
    • Go code.vikunja.io/api <= 2.5.0
    Fixed in
    2.6.0· Vendor fix available
    Issue
    The /dav, /.well-known, and /feeds groups are registered on the root Echo instance with only BasicAuth and no rate limiter. CalDAV BasicAuth accepts the plain account password, so password guessing over /dav is unbounded and never returns 429, while /api/v1/login is throttled from the tenth attempt. The only anti-brute-force control on the instance is therefore bypassable. Details pkg/routes/routes.go (~lines 238-249) registers /.well-known, /dav, and /feeds with middleware.BasicAuth(...) and nothing else; registerCalDavRoutes adds no limiter. pkg/routes/caldav/auth.go (~lines 88-93) falls through to user.CheckUserCredentials with the plain account password when no CalDAV token matches. In contrast, /register, /login, etc. are wrapped by unauthRateLimit() — an unconditional 10/min/IP pre-auth floor that ignores ratelimit.enabled (default false). TOTP-enabled accounts and bot users are correctly refused, so this targets password-only accounts. PoC (verified at runtime against…

    Recommended action: Upgrade to 2.6.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  16. Medium, CVSS 5.3GoAmendedPublished

    Vikunja: API token scopes bypassed via task expand parameter (comments, reactions, time entry counts)

    CVE-2026-91983 · GHSA-9rg3-v78m-26q8

    Affected
    • Go code.vikunja.io/api >= 1.0.0, <= 2.5.0
    Fixed in
    2.6.0· Vendor fix available
    Issue
    API token permission checks only match the HTTP method and route path. The expand query parameter on task read endpoints embeds data from other permission groups (task comments, reactions, time entry counts) without checking whether the token holds those scopes. A token scoped only to tasks read permissions can therefore read task comments and reactions it was explicitly not granted. Details models.CanDoAPIRoute (pkg/models/apiroutes.go, ~line 440) authorises API tokens purely by comparing method and c.Path() against the routes stored for each granted permission group. The query string is never consulted. The task read endpoints accept expand: - GET /api/v1/tasks/:task, GET /api/v1/tasks (pkg/models/tasks.go ReadOne/ReadAll, pkg/models/taskcollection.go) - GET /api/v2/tasks/:id, GET /api/v2/tasks, GET /api/v2/projects/:project/tasks (pkg/routes/api/v2/tasks.go, taskcollection.go) Accepted values include comments, commentcount, reactions, timeentriescount. addMoreInfoToTasks…

    Recommended action: Upgrade to 2.6.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  17. Medium, CVSS 5.3GoAmendedPublished

    Vikunja: Cross-tenant task-position rows can be injected into arbitrary project views via the unvalidated project_view_id in the task position endpoint (v1 and v2)

    CVE-2026-91984 · GHSA-w39f-h553-h2mx

    Affected
    • Go code.vikunja.io/api <= 2.5.0
    Fixed in
    2.6.0· Vendor fix available
    Issue
    The task-position endpoint authorizes only the task side of the write: TaskPosition.CanUpdate delegates to Task.CanUpdate (write access to the task's own project) and the request body's projectviewid is never validated to belong to the task's project, nor is any access to that view required. Any authenticated user with a single writable task of their own can persist (taskid, projectviewid, position) rows into any other tenant's project view (view IDs are small sequential integers and enumerable). Low position values (below MinPositionSpacing, 0.01) enter the recalculation branch, but RecalculateTaskPositions aborts on its own project read-access check before recalculating and the whole transaction rolls back, so no cross-tenant recalculation actually executes — only the plain row insert (position ≥ 0.01) persists. This is the same root-cause pattern as GHSA-569v-q83c-3j3g (kanban bucket relocation via projectviewid mass-assignment, fixed with a dual-side check for buckets in…

    Recommended action: Upgrade to 2.6.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  18. UnratedGoAmendedPublished

    Vikunja: Read-only project members can obtain any link share's access hash via the single-share read endpoint (v1 and v2) and escalate to the share's permission level

    CVE-2026-91985 · GHSA-qfwc-vx6f-3g6g

    Affected
    • Go code.vikunja.io/api <= 2.5.0
    Fixed in
    2.6.0· Vendor fix available
    Issue
    A user who has only read permission on a project can call the single link-share read endpoint and receive the share's hash field — the secret credential that the anonymous POST /shares/{share}/auth endpoint exchanges for a link-share JWT carrying the share's permission (read / read-write / admin). A read-only member can therefore mint a write- or admin-level token for the project and perform writes they are not entitled to, while their own user token is correctly refused. This is the remaining variant of the link-share hash disclosure class: GHSA-8hp8-9fhr-pfm9 fixed the list endpoint (ReadAll now requires project admin) but the single-read endpoint's gate was never aligned. Verified on Vikunja 2.5.0; the weak gate has existed since the endpoint, so earlier versions are likely affected too. Details Affected endpoints (both verified with a complete chain): - v1: GET /api/v1/projects/{project}/shares/{share} - v2: GET /api/v2/projects/{project}/shares/{share} Permission gate:…

    Recommended action: Upgrade to 2.6.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  19. Medium, CVSS 5.3GoAmendedPublished

    Vikunja: TOTP secret is readable after enrollment, no step-up auth

    CVE-2026-91982 · GHSA-88f6-4rjv-x774

    Affected
    • Go code.vikunja.io/api <= 2.5.0
    Fixed in
    2.6.0· Vendor fix available
    Issue
    Once 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. Details 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. This 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,…

    Recommended action: Upgrade to 2.6.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  20. High, CVSS 8.7GoAmendedPublished

    Vikunja: Every /api/v2 pre-auth endpoint is unthrottled on a stock install while its /api/v1 twin is rate limited

    CVE-2026-91972 · GHSA-6rvj-qwjf-3m4q

    Affected
    • Go code.vikunja.io/api <= 2.5.0
    Fixed in
    2.6.0· Vendor fix available
    Issue
    registerAPIRoutesV2 never applies the unconditional pre-auth rate-limit floor (unauthRateLimit()) to the v2 public routes — it passes that limiter only to /api/v2/ws — and otherwise relies on setupRateLimit, which registers nothing when ratelimit.enabled is false (the default). So on a stock install every v2 pre-auth endpoint (login, register, password-reset token, oauth token) is unthrottled, while its v1 twin is throttled. Details unauthRateLimit() - perMinuteIPRateLimit("noauth", RateLimitNoAuthRoutesLimit) (pkg/routes/ratelimit.go, ~lines 100-118) is an unconditional per-IP floor (default 10/60s) that deliberately ignores RateLimitEnabled, which is why v1's pre-auth routes are throttled even with the global limiter off. v1 applies it: ur := a.Group(""); ur.Use(unauthRateLimit()) (pkg/routes/routes.go ~line 459). registerAPIRoutesV2 (~lines 405-431) passes the unauthRateLimit() instance only to /api/v2/ws; its auth routes get only setupRateLimit(a, ...), which is…

    Recommended action: Upgrade to 2.6.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  21. High, CVSS 8.1GoAmendedPublished

    Vikunja: Plaintext storage of password-reset/email-confirm tokens in database enables account takeover on DB read access

    CVE-2026-62376 · GHSA-r6w9-259g-gwrv

    Affected
    • Go code.vikunja.io/api <= 2.3.0
    Fixed in
    2.4.0· Vendor fix available
    Issue
    Vikunja stores password-reset, email-confirmation, and account-deletion tokens in the usertokens table in plaintext. If an attacker gains read access to the database through a backup leak, misconfigured storage, or SQL-level exposure, they can immediately use pending tokens to take over user accounts without knowing passwords. Details pkg/user/token.go — genToken() stores the raw random string directly: Lookup also uses plaintext equality: Affected token types: - TokenPasswordReset (pkg/user/userpasswordreset.go:120) - TokenEmailConfirm (pkg/user/usercreate.go:101, pkg/user/updateemail.go:88) - TokenAccountDeletion (pkg/user/delete.go:102) Note: CalDAV tokens correctly use generateHashedToken with bcrypt — the same protection is absent for the above types. PoC Impact Any read access to the database (leaked backup, cloud misconfiguration, secondary SQLi) allows an attacker to take over every user account with a pending reset token within the 24-hour token lifetime. Full…

    Recommended action: Upgrade to 2.4.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  22. High, CVSS 7.5GoAmendedPublished

    Vikunja: OIDC email-fallback account linking ignores email_verified, enabling local-account takeover

    CVE-2026-62367 · GHSA-xv7q-fvmc-jx96

    Affected
    • Go code.vikunja.io/api >= 1.0.0, <= 2.3.0
    Fixed in
    2.4.0· Vendor fix available
    Issue
    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: getUser resolves this via s.Get(), which ANDs non-zero fields - WHERE issuer='local' AND email=?. Local users always have Issuer="local"…

    Recommended action: Upgrade to 2.4.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  23. High, CVSS 7.5GoAmendedPublished

    Vikunja: Link-share principal-type confusion enables cross-account team removal, bot takeover, and roster disclosure

    CVE-2026-76216 · GHSA-32r8-5843-4qw2

    Affected
    • Go code.vikunja.io/api < 2.5.0
    Fixed in
    2.5.0· Vendor fix available
    Issue
    Vikunja's `web.Auth` interface (`pkg/web/web.go`, single method `GetID() int64`) is satisfied by BOTH `*user.User` and `*models.LinkSharing`. A link-share's `GetID()` returns the raw positive `share.ID` (`pkg/models/link_sharing.go:83-85`), which lives in the same positive autoincrement ID space as `users.id`. The safe negated form `getUserID() = share.ID * -1` (`link_sharing.go:126-128`) exists but is NOT used at three permission sinks. As a result, a link-share principal with id `N` — which should have zero authority over teams or bot users — is treated as the *user* whose `users.id == N` at three permission checks that lack the `a.(*LinkSharing)` guard their sibling methods have. This is the same principal-type-confusion class as CVE-2026-68581 (GHSA-vvcv-vpph-h844), but at three code paths that advisory/fix never touched. Root Cause `web.Auth` is a one-method interface (`GetID() int64`). `*LinkSharing.GetID()` returns the raw positive share id. Three permission…

    Recommended action: Upgrade to 2.5.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  24. Critical, CVSS 9.3GoAmendedPublished

    Vikunja: Link-share token reads any tenant's kanban buckets and enumerates usernames/IDs instance-wide (BOLA)

    CVE-2026-68582 · GHSA-rj9j-8772-4h6c

    Affected
    • Go code.vikunja.io/api >= 0.24.0, <= 2.3.0
    Fixed in
    2.4.0· Vendor fix available
    Issue
    The task-collection endpoint GET /api/v1/projects/{project}/views/{view}/tasks loads the requested project view straight from the URL path without verifying the caller is authorized for it. For a link-share token, the task query is correctly pinned to the share's own project, but the view is taken from the attacker-controlled path and never re-validated against the share. A holder of a share link to any project can therefore point the endpoint at any other tenant's kanban view and receive that view's bucket records — bucket titles plus the full createdby user object (username, name, id) — for every view in the instance. The same missing pre-authorization view load also yields a project/view-ID existence oracle (404 vs. non-404) usable by link shares and ordinary authenticated users alike. Details Root cause is in TaskCollection.ReadAll (pkg/models/taskcollection.go). 1. The view is resolved from the URL params before any permission check: GetProjectViewByIDAndProject…

    Recommended action: Upgrade to 2.4.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  25. High, CVSS 8.1GoAmendedPublished

    Vikunja: Link-share principal ID collision allows cross-account API token issuance and management

    CVE-2026-68581 · GHSA-vvcv-vpph-h844

    Affected
    • Go code.vikunja.io/api >= 0.22.0, <= 2.3.0
    Fixed in
    2.4.0· Vendor fix available
    Issue
    Executive Summary Vikunja accepts both regular-user JSON Web Tokens (JWTs) and link-share JWTs through its generic authenticated API route group. A link-share JWT resolves to a models.LinkSharing principal whose GetID() method returns the numeric linkshares.id. The API-token management model then treats that generic numeric value as a users.id when it creates, lists, and deletes API tokens. Because users.id and linkshares.id are independent positive sequences, a link share whose ID equals another user's ID is treated as that user by /api/v1/tokens. An ordinary authenticated attacker can obtain a target's numeric user ID through authenticated user search and create link shares on an attacker-writable project until the link-share sequence reaches that value. The colliding link-share principal can then list the target's API-token metadata, issue a new API token owned by the target, and delete target-owned API tokens. The newly issued token operates with attacker-selected valid API…

    Recommended action: Upgrade to 2.4.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →