mediumCVSS 6.5Vulnerability

GHSA-hjx8-qv73-f7cm

## Summary A collaborator removed from a project keeps a **live, automatic feed** of that project's contents, because nothing on any revocation path deletes the webhook they created while they had access. Vikunja already has a revocation-cleanup routine that deletes other derived rows for exactly this reason. Its set is `{task_assignees, subscriptions}`. **`webhooks` and `link_shares` — the only two rows that carry a live channel into the project — are not in it**, and the routine is wired to one of four revocation paths. ## Details `pkg/models/teams.go:411` — `cleanupTaskMembersAfterTeamRemoval`, added in `9358954c9`, whose commit message states the invariant: *"cleanup team memberships, assignments and subscriptions when users lose access to a project"*. ```go canRead, _, permErr := project.CanRead(s, &user.User{ID: memberID}) ... if !canRead { projectsToCleanup = append(projectsToCleanup, projectID) } ... _, err = s.In("task_id", taskIDs).And("user_id = ?", memberID). Delete(&TaskAssginee{}) _, err = s.In("entity_id", taskIDs). Where("entity_type = ? AND user_id = ?", SubscriptionEntityTask, memberID). Delete(&Subscription{}) _, err = s.In("entity_id", projectsToCleanup). Where("entity_type = ? AND user_id = ?", SubscriptionEntityProject, memberID). Delete(&Subscription{}) ``` So you have already decided that losing read access must delete rows the departing user left behind, and that the test is a live `project.CanRead`. The gap is which rows are in the set. **And there is a second level, which is the sharper one.** That routine has exactly one caller: ``` pkg/models/listeners.go:1642 err = cleanupTaskMembersAfterTeamRemoval(s, event.Team.ID, event.Member.ID) ``` against four revocation paths: ``` pkg/models/project_team.go:151 TeamProject.Delete pkg/models/project_users.go:141 ProjectUser.Delete <- grep -c cleanup inside: 0 pkg/models/project_users.go:248 ProjectUser.Update <- the downgrade path pkg/model

Properties

severity
medium
summary
Vikunja: Webhooks and link shares survive every revocation path, so a removed collaborator keeps a live feed
cvss_score
6.5
retrieved_at
2026-10-10T02:17:04+00:00
ghsa_published
2026-10-09T20:57:41Z
source_url
https://github.com/advisories/GHSA-hjx8-qv73-f7cm
ghsa_updated
2026-10-09T20:57:42Z
ghsa_id
GHSA-hjx8-qv73-f7cm
last_source
GitHub Advisory Database
cve_id
GHSA-hjx8-qv73-f7cm
cvss_vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
signal_observed_at
2026-10-10T02:17:04+00:00
is_ghsa_only
true

Related Entities (5)

VULNERABLE_TO (1)

←[Software]go/code.vikunja.io/api

AFFECTS (1)

→[Software]go/code.vikunja.io/api

HAS_WEAKNESS (2)

→[Weakness]Incorrect Authorization
→[Weakness]Insufficient Session Expiration

REPORTED_BY (1)

→[Source]GitHub Advisory Database

Explore deeper with Ninja Signal's threat intelligence graph

GHSA-hjx8-qv73-f7cm (CVSS 6.5) — Ninja Signal Threat Intelligence | Ninja Signal