CVE-2026-58437: Gitea Repository Visibility Manipulation via Git Push Options
Any user with admin or owner access to a Gitea repository can silently toggle its visibility from private to public using a standard git push flag, leaving no audit trail or webhook event behind.
The problem
Gitea's post-receive hook handler reads two push options, `repo.private` and `repo.template`, and applies them to any existing repository when supplied during a `git push -o` call.
The visibility change is written directly to the database using `UpdateRepositoryColsNoAutoTime`, which suppresses the `updated_at` timestamp. No activity log entry is created, no `repository` webhook fires, and no org notification is sent. The change is indistinguishable from a normal push in the repository activity feed.
Proof of concept
A working proof-of-concept for CVE-2026-58437 in code.gitea.io/gitea, with the exact payload below.
# Step 1: clone the target repo
git clone http://USER:PASSWORD@<gitea-host>/OWNER/REPO.git /tmp/target
cd /tmp/target
# Step 2: make any commit (the option rides on a real push)
echo patch >> .gitkeep && git add . && git commit -m "routine update"
# Step 3: push with the visibility option -- makes the private repo public
git push http://USER:PASSWORD@<gitea-host>/OWNER/REPO.git main \
-o repo.private=false
# Step 4: optionally restore and cover tracks
git push http://USER:PASSWORD@<gitea-host>/OWNER/REPO.git main \
-o repo.private=true
# The activity feed shows only two normal push events.The push option constants `repo.private` and `repo.template` were designed for Gitea's push-to-create flow, where a repository does not yet exist. The handler in `routers/private/hook_post_receive.go` (lines 173-225) applies them unconditionally to already-existing repositories whenever the pusher holds owner or admin-collaborator access.
The root cause is the absence of a `wasEmpty` guard: the options are processed regardless of whether the repository pre-existed. The database write uses `UpdateRepositoryColsNoAutoTime`, deliberately skipping timestamp updates and bypassing the normal visibility-change service that would fire webhooks and write audit logs.
The patch (PR #38323) hardens the push option handling so that `repo.private` and `repo.template` are rejected for repositories that already exist, restricting them to the push-to-create path only. CWE-284 (Improper Access Control).
The fix
Upgrade to Gitea 1.27.0. The patch (PR #38323) gates `repo.private` and `repo.template` push options so they are only processed during push-to-create (when the repository did not previously exist). On existing repositories these options are now ignored. No config change is required beyond upgrading.
Reported by prakhar0x01.
Related research
- highCVE-2026-58422CVE-2026-58422: Gitea OAuth2 Callback Improper Access Control Silently Re-enables Disabled Accounts
- high · 7.5CVE-2026-24451CVE-2026-24451: Gitea Fork Sync Information Disclosure via merge-upstream
- critical · 9.8CVE-2026-20896CVE-2026-20896: Gitea Docker Image Authentication Bypass via Spoofed X-WEBAUTH-USER Header
- high · 7.5CVE-2026-58421CVE-2026-58421: Gitea CODEOWNERS ReDoS via Unbounded regexp2 Match