Gitea Token Scope Bypass: Public-Only Restrictions Not Enforced on Private PR Head Repositories
A scope-validation bypass in Gitea allows attackers with public-only repository tokens to write to private pull request head branches via the public base repository API route. This circumvents intended token restrictions and enables unauthorized repository modifications.
CVE References
Affected
Vulnerability Description
This is an authorization scope-enforcement vulnerability stemming from inconsistent token restriction validation across repository contexts. Gitea's token model includes a public-only flag that should restrict API operations to public repositories. However, the PR update endpoint (POST /api/v1/repos/{public-owner}/{public-repo}/pulls/{index}/update) validates the public-only restriction only against the base repository (which is public), but then proceeds to update the head repository without re-validating the token's scope restrictions. If the head repository is private, the token bypass succeeds because the authorization check uses standard RBAC against the user account rather than re-enforcing the token's public-only constraint.
Root Cause & Impact
The root cause is a context-switch vulnerability: scope restrictions are enforced at the route layer (ctx.Repo.Repository = base repo), but the business logic (UpdatePullRequest()) operates across two repositories without re-validating token constraints for secondary contexts. An attacker with a leaked or intentionally-scoped public-only token can exploit cross-repository operations to inject commits into private repositories, compromising repository integrity and enabling supply-chain attacks.
Detection Guidance
Log Indicators:
POST /api/v1/repos/*/pulls/*/updaterequests from tokens withpublic_only=truescope followed by write operations to private repositories- Token activity logs showing public-only tokens performing write operations outside public repos
- PR update operations where base repo is public but head repo is private
Audit Checks:
- Monitor API audit logs for mismatches between token scope and repository visibility
- Correlate token creation scope with actual repository write operations
- Flag any public-only token with write activity against private repositories
Mitigation Steps
- Immediate: Update Gitea to a patched version (check official advisories for version number)
- Workaround: Restrict token issuance—avoid granting
write:repositoryscopes withpublic_onlyflag to untrusted principals - Configuration: Review existing public-only tokens with write access; audit their activity logs
- Code-level fix: Re-validate token scope restrictions in
UpdatePullRequest()before operating on the head repository; enforce scope checks at both repository contexts, not just the route layer
Risk Assessment
Likelihood: Medium-High — The vulnerability requires a legitimate but scoped token (public-only + write access), which is a realistic configuration for CI/CD or bot workflows. Attackers with insider access or leaked tokens can exploit this reliably.
Threat Actor Interest: High — This enables supply-chain compromise if exploited against CI/CD systems with scoped bot tokens. DevOps/security teams often create public-only tokens to limit blast radius, making this a high-value target for post-compromise privilege escalation.
Sources