A AegiFlow
MEDIUMCVSS 4.3

CVE-2026-58510

Gitea: GHSA-8fwc-qjw5-rvgp ClearRepoWatches fix not applied to API EditRepo path — sister code path retains stale watches on public->private

Published
2026-07-21
Modified
2026-07-21
Aliases
GHSA-q423-49rw-g9mh
Sources
github-advisory

Summary

## Summary GHSA-8fwc-qjw5-rvgp ("Gitea may send release notification emails for private repositories to users whose access has been revoked", fix in PR #36319 / commit 8a98ac22) added `repo_model.ClearRepoWatches` as a defense for the state transition public→private. The cleanup was wired into `services/repository/repository.go::MakeRepoPrivate` only. The sister helper `services/repository/repository.go::updateRepository` — which is the function used by the API path `PATCH /api/v1/repos/{owner}/{repo}` — was not patched and still calls `ClearRepoStars` only. As a result, when a public repository is flipped to private via the REST API (rather than via the web Settings → Danger Zone UI), the watch records persist. Affected users can: - See the now-private repository in `GET /api/v1/user/subscriptions?private=true` along with its full `Repository` JSON (description, default branch, language, fork status, counts, mirror metadata, license list, etc.) — even though they have no access to the repository. - Have their stale watch records re-leak content through any future notification path that does not include the send-time `CheckRepoUnitUser` check that was added to `services/mailer/mail_release.go`. - Inflate the visible `NumWatches` counter on the repository. ## Severity Medium — `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N` Same impact class as the original GHSA-8fwc-qjw5-rvgp (which was classified Medium). The send-time mail filter added in the same PR mitigates the release-content disclosure vector. The residual leak is repo metadata via the subscriptions endpoint and stale watcher counts. CWE-281 (Improper Preservation of Permissions), CWE-359 (Exposure of Private Personal Information), CWE-200 (Exposure of Sensitive Information). ## Affected Versions Every release starting from v1.25.4 (the release shipping the original GHSA-8fwc-qjw5-rvgp fix) through HEAD (master @ `ef801bb6`, 2026-05-16). The follow-up refactor in commit `943ff752` (PR #36959, 2026-03-24) which merged `MakeRepoPublic`+`MakeRepoPrivate` did not propagate the `ClearRepoWatches` call to `updateRepository`. ## Affected Component - `services/repository/repository.go:240-302` — `func updateRepository(ctx, repo, visibilityChanged bool)`, the sister helper called via the API path. Clears stars on line 273 but never calls `ClearRepoWatches`. - `routers/api/v1/repo/repo.go::Edit` (line 573) → `updateBasicProperties` (line 678-697) → `repo_service.UpdateRepository(ctx, repo, visibilityChanged)` (line 726) — the API path that exercises the sister helper. ## Steps to Reproduce The bug is observable purely from static analysis; the live PoC is straightforward. 1. Start a Gitea instance at any release from v1.25.4 onwards (verified static at HEAD `ef801bb6`). 2. Create users `A` (org admin) and `B` (member). Create a public repository `A/proj`. As `B`, watch the repo: ``` curl -u B: -X PUT "https://gitea.example.com/api/v1/repos/A/proj/subscription" ``` 3. As `A`, flip the repo to private via the REST API (not via the web UI): ``` curl -u A: -X PATCH "https://gitea.example.com/api/v1/repos/A/proj" \ -H 'Content-Type: application/json' \ -d '{"private": true}' ``` 4. As `B`, list `B`'s watched repos with `private=true`: ``` curl -u B: "https://gitea.example.com/api/v1/user/subscriptions" ``` The now-private repo `A/proj` is returned in `B`'s subscription list, with the full `Repository` payload — including `description`, `default_branch`, `language`, `topics`, `license`, fork/branch/issue/release counts, etc. 5. Compare with the web-UI path (which IS patched). As `A`, flip a different public repo `A/proj2` to private via Settings → Danger Zone → "Make this repository private" (which calls `repo_service.MakeRepoPrivate`). Verify `B`'s subscription list no longer contains `A/proj2`. The asymmetry of outcomes between steps 4 and 5 — for the same state transition — is the gap. ## Direct E

Affected packages

EcosystemPackageAffected versionsFixed versions
Gocode.gitea.io/gitea1.27.0

Remediation: Upgrade to 1.27.0 or later.

References

Includes data from the GitHub Advisory Database, licensed under CC-BY 4.0.

CVE® is a registered trademark of The MITRE Corporation. CVE content reproduced under the CVE Terms of Use; copyright designation © MITRE.