Seven Gitea API routes under /api/v1/users/{username} (followers, following, following/{target}, starred, subscriptions, keys and gpgkeys) were registered without the individualPermsChecker middleware that enforces the visibility of the target user. An authenticated user could therefore read the followers, following list, starred and watched repositories and public SSH and GPG keys of a user with limited or private visibility, whom they could not otherwise see. The issue was fixed in 1.27.3 and 28.0.0 and disclosed with 28.2.0.
Deleting a label compared the ID of the repository in the request against the organization ID of organization labels, and the two ID sequences overlap. A user with write access to the issues of a repository could therefore delete the labels of an organization that has the same numeric ID as that repository. Labels are now deleted only within their own repository or organization.
Adding attachments to a release checked the repository and release of an attachment but not whether it was already linked to an issue or comment. A user with write access to the releases of a repository, who knew the UUID of an attachment in that repository, could link it to a release. This exposed the file name, size and download count of the attachment through the release and allowed the user to rename or delete it.
The visibility check of Gitea user profiles was applied to GET requests only, while POST /{username} (follow and unfollow) required only a signed-in user. Any authenticated user could therefore obtain the full name, location, website and description of a user with a private profile from the response. The issue was fixed in 28.1.0 and disclosed with 28.2.0.
Creating a draft release through the API returned an assets list that was built from a release without an ID, which matched every attachment that was not linked to a release. A user who could create a draft release in a repository therefore received the metadata (file name, UUID, upload time, size and download count) of issue and comment attachments of repositories they could not read, and of abandoned uploads.
GET /api/v1/user/subscriptions returned the metadata of every repository a user was watching without checking that the user still had access to it. A user who watched a private repository while having access, and later lost it, for example through a team permission downgrade, could still read its name, description, clone URLs, owner and counters. The issue was fixed in 1.27.0 and 28.0.0 and disclosed with 28.2.0.
The Gitea web handlers for adding and removing reactions on issues and comments did not refuse locked issues for users without write access, although the API did. A signed-in user who could read an issue could therefore add or remove reactions on a locked issue and its comments, bypassing the interaction restriction of the lock. Only reactions were affected; no content could be changed.
POST /{owner}/{repo}/topics was registered without the sign-in middleware that provides the cross-origin protection, so a request issued by a third-party site was not rejected. A repository administrator who visited a malicious page could have the topics of their repository changed. No other repository settings were reachable through this route.
The Gitea Actions artifact v4 (Twirp) handlers read the whole request body into memory without a size limit. A user who can run a workflow and obtains the runner token of that run could send an oversized request to the artifact service and exhaust the memory of the server, which terminates the Gitea process. The request body is now limited to 1 MiB.
Requesting /{username}/-/repositories for an individual user instead of an organization made the organization home handler dereference a nil organization and panic. The request needs no authentication and no special configuration. The server answered with an HTTP 500 error and logged a panic for each request; the fix returns 404 for individual users.
Gitea resolved the principals of an SSH certificate by searching the content of all stored public keys instead of only principal keys. When Gitea trusts a user certificate authority (SSHTRUSTEDUSERCAKEYS) and accepts arbitrary principals (SSHAUTHORIZEDPRINCIPALSALLOW=anything), a user could register another user's public key line as their own principal, or a holder of a certificate signed by that authority could list it, and then authenticate as the owner of that key through the HTTP signature API and the built-in SSH server. Instances that do not trust a user certificate authority are not affected.
The Gitea OpenID association callback in the security settings accepted a positive OpenID 2.0 assertion without checking that the signed-in user had started the linking. Because OpenID 2.0 allows unsolicited assertions, an attacker-controlled OpenID provider could attach the attacker's identity to the account of a signed-in victim who opened a crafted link, and the attacker could then sign in as the victim through OpenID login, which does not apply the local TOTP or WebAuthn checks. The callback now requires a time-limited state value bound to the user.
Gitea's web attachment handler skips its cross-repository ownership check for attachments created before 16 January 2026 and checks permissions against the repository named in the request URL instead. An unauthenticated attacker who knows a private attachment's UUID can request it through a public repository's attachment path and retrieve its contents. This can expose issue and pull request attachments or release assets; the random attachment UUID must already be known to the attacker.
When OpenID sign-in is enabled, Gitea processes unauthenticated assertion parameters and sends an HTTP POST request to the caller-supplied OpenID provider endpoint during verification. An attacker controls the destination and much of the form body, allowing interaction with internal HTTP services reachable from the Gitea server. The response is not returned to the attacker, so the issue is blind SSRF; its impact depends on the services and network addresses the server can reach.
Gitea's collaboration access-mode endpoint accepts the Owner access mode from an authenticated repository collaborator with Admin access. The collaborator can promote their effective permissions from Admin to Owner and then perform owner-only operations, including transferring the repository to their own account. This bypasses the intended boundary between repository administration and ownership.
Gitea allows a token with write:user scope to register an attacker-controlled SSH public key on the token owner's account. API requests signed with the corresponding private key authenticate as that account through HTTP Signature without API token scope information, causing route-level token scope checks to be skipped. This converts a user-scoped token into an unscoped API authentication method while retaining the account's normal role and repository permissions.
Gitea resolves local reusable workflow files from a fork's head commit when a trusted base-branch workflow runs for a pullrequesttarget event. A fork author can modify a referenced reusable workflow so attacker-controlled code executes with the repository and organization secrets available to that event. Exploitation requires a base workflow that calls a local reusable workflow, and bypasses the intended separation between trusted base code and untrusted fork code.
Gitea substitutes a URL derived from the markup Context field into external renderer command templates without escaping the reference path before shell-style argument splitting. A crafted Context can inject additional renderer arguments, including options that load executable filter files. On deployments using a susceptible external renderer such as pandoc, a user who can place a filter file at an accessible path can cause it to execute as the Gitea service account; the public repository markup endpoint itself can be reachable without authentication.
Gitea's OpenID connect handler accepts a user's password without enforcing enrolled TOTP or WebAuthn verification before completing sign-in and linking an OpenID identifier. When OpenID sign-in is enabled, an attacker who knows the victim's password can obtain a session and link an attacker-controlled identifier. The attacker can then sign in through that identifier without the victim's password or second factor, and a password change does not remove the link.
Gitea's Maven upload handler reads checksum uploads entirely into memory and returns before enforcing package-size quotas. An authenticated user with package-publish permission can submit an oversized body to a checksum endpoint despite legitimate checksum values being at most 128 bytes. This bypasses the upload quota on that path and can exhaust server memory.
Gitea uses inconsistent repository visibility predicates, and the condition used by some repository-listing endpoints admits repositories whose owners are hidden from the viewer. Those listings disclose repository metadata even though direct routes correctly deny access with a 404 response. The issue exposes repository existence and listing information across the intended owner-visibility boundary.
Gitea does not limit the length of the gitignores field accepted by repository-creation forms and the API. Repository initialization splits the field into template names, repeatedly reads the referenced templates, and buffers their contents in memory. An attacker who can create repositories can submit an oversized value to amplify template reads and memory use, impairing availability.
Gitea's Actions workflow status badge endpoint does not enforce repository-read scope or the public-only restriction on the token authenticating the request. A token lacking read:repository, or restricted to public repositories, can retrieve the latest workflow status of a private repository accessible to its owner. This discloses private workflow status beyond the token's intended delegated permissions.
Gitea's repository markup endpoint resolves same-repository pull request references without enforcing the viewer's Pull Requests permission. A member with only Wiki access to a private repository can submit a markup preview request and retrieve a private pull request's title and state icon despite lacking Issues and Pull Requests access. This exposes pull request metadata across repository unit permissions.
Gitea's pull request review notifier does not attach the pull request to the Actions notification, so the fork workflow approval gate does not recognize the run as originating from a fork. Review comment and review approval or rejection events can consequently load workflow code from the fork head and run it on the base repository's runners without the required maintainer approval. This allows execution of fork-controlled workflow code across the intended approval boundary.
Gitea's organization-list API does not enforce the read:organization token scope. A token limited to another category, such as read:misc, can retrieve organization metadata visible to its owner. For a site administrator's token, the response can include Limited and private organizations, bypassing the intended restriction on the token's delegated access.
Gitea's shared comparison helper omits the token repository-access check used when updating pull requests. A public-only token with read:repository scope can route a comparison or pull request creation through a public base repository and retrieve commit history and diffs from a private head repository accessible to the token owner. This bypasses the token's public-only restriction; it does not remove the account's underlying repository permission checks.
Gitea creates server-side Git hook directories and scripts with mode 0777 and relies on the process umask to restrict access. With a permissive umask such as 0000 or 0002, another local user who can reach the repository storage may modify a hook or add an executable to a writable hook directory. A later Git operation can execute that file as the Gitea service account.
Gitea's repository migration API accepts a public-only token when the request specifies creation of a private repository. A delegated token intended to operate only on public resources can create a private repository and migration task under the authorizing account or an organization where that user has the necessary permissions. The ordinary private repository-creation route rejects the same token, but the migration path omits that restriction.
Gitea's organization repository-creation API requires write:organization but omits the write:repository token scope enforced by other repository-creation routes. A personal access token or OAuth application token without repository-write scope can therefore create organization-owned repositories if the authorizing user has permission to do so. This bypasses the token's delegated scope boundary while remaining subject to the user's organization permissions.