Описание
Gitea: Branch Protection Bypass via PR Retargeting Preserves Stale official Approval Flag
Summary
Gitea does not re-evaluate the official flag on existing pull request reviews when a PR's target branch is changed. An attacker with write access to a repository can obtain an official: true approval on a PR targeting an unprotected branch, then retarget the PR to a protected branch (e.g., master). The approval, which would have been official: false if submitted against the protected branch, is preserved and satisfies the protected branch's required approvals, allowing the attacker to merge without legitimate maintainer approval.
- Confirmed on Gitea 1.25.4 (
1.25.4+41-g96515c0f20)
Vulnerability Details
Root Cause
When a review is submitted on a pull request, Gitea computes the official flag by checking whether the reviewer is in the target branch's approval whitelist (IsUserOfficialReviewer in models/git/protected_branch.go). This flag is stored in the database as a boolean on the review record.
When a PR's target branch is subsequently changed via ChangeTargetBranch (services/pull/pull.go:218), the function:
- Updates
pr.BaseBranch - Recalculates merge feasibility and divergence
- Deletes old push comments
- Creates a "change target branch" comment
But it does not:
- Re-evaluate
officialon existing reviews - Dismiss existing approvals
- Check whether reviewers are in the new target branch's approval whitelist
At merge time, GetGrantedApprovalsCount (models/issues/pull.go:766) counts reviews where official = true AND dismissed = false AND type = Approve. It reads the stored boolean — it does not re-check the whitelist. The stale official: true from the unprotected branch satisfies the protected branch's approval requirement.
Relevant Code Paths
- Review creation —
services/pull/review.go:SubmitReviewcallsIsOfficialRevieweragainst the currentpr.BaseBranch's protection rules, storesofficial=true/false - Target branch change —
services/pull/pull.go:ChangeTargetBranchmodifiespr.BaseBranchbut does not touch existing reviews - Merge check —
services/pull/check.go:CheckPullMergeable→models/issues/pull.go:GetGrantedApprovalsCountcounts storedofficial=truereviews without re-evaluating against the new branch's whitelist
Prerequisites
The attacker needs:
- Write (push) access to the repository (collaborator with write role, or the ability to create branches — not admin)
- The ability to create pull requests (standard for any user with push access)
- A second account (or any non-admin account) to submit the approval on the unprotected branch
The attacker does not need:
- Admin access
- To be in the approval whitelist for the protected branch
- Any interaction from the branch protection's designated approvers
Proof of Concept
Setup
Repository owner/repo with branch master protected:
- Required approvals: 1
- Approval whitelist enabled, containing only user
admin-reviewer - User
attackerhas write access but is not in the approval whitelist
Steps
Observed API Responses
Step 4 — Approval on unprotected branch:
Step 6 — Same approval after retarget to protected master:
The official flag is unchanged. Under the protected branch's rules, this user's approval should be official: false.
Impact
- Branch protection bypass: Protected branches with approval whitelists can be merged into without any whitelisted user approving
- Privilege escalation: A user with write-but-not-admin access can effectively nullify the admin-configured approval requirements
Suggested Fix
Re-evaluate the official flag on all existing reviews when a PR's target branch changes. In services/pull/pull.go:ChangeTargetBranch, after updating pr.BaseBranch:
Alternatively, dismiss all existing approvals on retarget (simpler, more conservative):
Ссылки
- https://github.com/go-gitea/gitea/security/advisories/GHSA-w5pg-649r-p6gg
- https://github.com/go-gitea/gitea/pull/38319
- https://github.com/go-gitea/gitea/pull/38402
- https://github.com/go-gitea/gitea/commit/74ad781db9c37134ee9280c69a6b1de53801503e
- https://github.com/go-gitea/gitea/commit/8401fe7c544abff1ecc49d7f3166fd4ee0c174ef
- https://github.com/go-gitea/gitea/releases/tag/v1.27.0
Пакеты
code.gitea.io/gitea
< 1.27.0
1.27.0
Связанные уязвимости
Branch Protection Bypass via PR Retargeting Preserves Stale `official` Approval Flag
Branch Protection Bypass via PR Retargeting Preserves Stale `official` Approval Flag