{"id":"GHSA-8wvg-r2j4-3737","aliases":["GO-2026-6723"],"status":"published","title":"Vikunja: Assignee email addresses disclosed to read-only project members via the task assignees endpoint","description":"### Summary\n`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.\n\n### Details\n`pkg/models/task_assignees.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/project_users.go:216`, `pkg/models/teams.go:177`, `pkg/models/label_task.go:312`, `pkg/models/task_attachment.go:511`. The omission here reads as an oversight, not a decision.\n\nThe same file's `getRawTaskAssigneesForTasks` (~line 56) also selects `users.*` but is safe because its only caller (`addAssigneesToTasks`) blanks the email afterwards.\n\n### PoC (verified at runtime against v2.5.0, v1 and v2)\n```\nGET /api/v1/tasks/{id}/assignees   (reader with permission:0)\n-\u003e [{\"id\":37,\"username\":\"...\",\"email\":\"assignee+SECRET@example.test\", ...}]\n```\nSame leak on `GET /api/v2/tasks/{id}/assignees` (routes through the identical model method). Contrast: `GET /api/v1/projects/{id}/projectusers` and the project task-embed both return the same users with no email.\n\n### Impact\nDisclosure of assignees' email addresses to users who should only see usernames. Read-only.\n\n### Fix\nBlank `Email` on each returned user in `TaskAssginee.ReadAll` before returning, matching the sibling paths. Covers v1 and v2 at once.","severity":{"version":"4.0","score":5.3,"vector":"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","level":"medium","from":"ghsa"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-200"],"published":"2026-10-09T20:54:49Z","modified":"2026-10-19T21:41:23Z","fixes":[{"ecosystem":"Go","package":"code.vikunja.io/api","fixed_in":["2.6.0"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"Go","package":"code.vikunja.io/api","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"2.5.0"},{"fixed":"2.6.0"}]}]},{"source":"osv","ecosystem":"Go","package":"code.vikunja.io/api","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"2.6.0"}]}]},{"source":"osv","ecosystem":"Go","package":"code.vikunja.io/api","ranges":[{"type":"SEMVER","events":[{"introduced":"0"}]}]}],"references":[{"url":"https://github.com/go-vikunja/vikunja/security/advisories/GHSA-8wvg-r2j4-3737","tags":["web","advisory"]},{"url":"https://github.com/go-vikunja/vikunja/pull/3688","tags":["web"]},{"url":"https://github.com/go-vikunja/vikunja/releases/tag/v2.6.0","tags":["web"]},{"url":"https://github.com/advisories/GHSA-8wvg-r2j4-3737"},{"url":"https://github.com/go-vikunja/vikunja","tags":["package"]}],"sources":{"ghsa":[{"id":"GHSA-8wvg-r2j4-3737","title":"Vikunja: Assignee email addresses disclosed to read-only project members via the task assignees endpoint","description":"### Summary\n`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.\n\n### Details\n`pkg/models/task_assignees.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/project_users.go:216`, `pkg/models/teams.go:177`, `pkg/models/label_task.go:312`, `pkg/models/task_attachment.go:511`. The omission here reads as an oversight, not a decision.\n\nThe same file's `getRawTaskAssigneesForTasks` (~line 56) also selects `users.*` but is safe because its only caller (`addAssigneesToTasks`) blanks the email afterwards.\n\n### PoC (verified at runtime against v2.5.0, v1 and v2)\n```\nGET /api/v1/tasks/{id}/assignees   (reader with permission:0)\n-\u003e [{\"id\":37,\"username\":\"...\",\"email\":\"assignee+SECRET@example.test\", ...}]\n```\nSame leak on `GET /api/v2/tasks/{id}/assignees` (routes through the identical model method). Contrast: `GET /api/v1/projects/{id}/projectusers` and the project task-embed both return the same users with no email.\n\n### Impact\nDisclosure of assignees' email addresses to users who should only see usernames. Read-only.\n\n### Fix\nBlank `Email` on each returned user in `TaskAssginee.ReadAll` before returning, matching the sibling paths. Covers v1 and v2 at once.","status":"published","published":"2026-10-09T20:54:49Z","modified":"2026-10-09T20:54:51Z","cvss":[{"version":"4.0","score":5.3,"vector":"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","level":"medium"}],"cwes":["CWE-200"],"updated_at":"2026-11-02T14:41:31.175024Z"}],"osv":[{"id":"GHSA-8wvg-r2j4-3737","title":"Vikunja: Assignee email addresses disclosed to read-only project members via the task assignees endpoint","description":"### Summary\n`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.\n\n### Details\n`pkg/models/task_assignees.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/project_users.go:216`, `pkg/models/teams.go:177`, `pkg/models/label_task.go:312`, `pkg/models/task_attachment.go:511`. The omission here reads as an oversight, not a decision.\n\nThe same file's `getRawTaskAssigneesForTasks` (~line 56) also selects `users.*` but is safe because its only caller (`addAssigneesToTasks`) blanks the email afterwards.\n\n### PoC (verified at runtime against v2.5.0, v1 and v2)\n```\nGET /api/v1/tasks/{id}/assignees   (reader with permission:0)\n-\u003e [{\"id\":37,\"username\":\"...\",\"email\":\"assignee+SECRET@example.test\", ...}]\n```\nSame leak on `GET /api/v2/tasks/{id}/assignees` (routes through the identical model method). Contrast: `GET /api/v1/projects/{id}/projectusers` and the project task-embed both return the same users with no email.\n\n### Impact\nDisclosure of assignees' email addresses to users who should only see usernames. Read-only.\n\n### Fix\nBlank `Email` on each returned user in `TaskAssginee.ReadAll` before returning, matching the sibling paths. Covers v1 and v2 at once.","status":"published","published":"2026-10-09T20:54:49Z","modified":"2026-10-19T21:41:23.40516557Z","cvss":[{"version":"4.0","score":5.3,"vector":"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","level":"medium"}],"cwes":["CWE-200"],"updated_at":"2026-11-02T15:46:42.78452Z"},{"id":"GO-2026-6723","title":"Vikunja: Assignee email addresses disclosed to read-only project members via the task assignees endpoint in code.vikunja.io/api","description":"Vikunja: Assignee email addresses disclosed to read-only project members via the task assignees endpoint 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.6.0.","status":"published","published":"2026-10-19T21:08:26Z","modified":"2026-10-19T21:31:36.963583258Z","updated_at":"2026-11-02T15:47:03.11707Z"}]}}
