We are excited to announce the release of Gitea 28.2.0, the second maintenance release for the 28 series. It contains security fixes and a number of bug fixes for Actions, pull requests, authentication and packages. We strongly recommend that all users upgrade as soon as possible.
This release addresses the following security vulnerabilities. Please upgrade as soon as possible.
CVE-2026-109553: SSH certificate principals were looked up among all stored public keys instead of only principal keys, so a certificate listing another user’s public key as a principal authenticated as that user when the trusted user CA accepts arbitrary principals. Fixed by #39839 / #39847. Thanks to @DshtAnger for reporting the issue, and to @silverwind, @wxiaoguang and @bircni for the patch.
CVE-2026-104627: The OpenID association callback in the security settings did not check that the logged-in user had started the linking, so an unsolicited assertion from an attacker-controlled OpenID provider could attach the attacker’s identity to a victim’s account and later be used to sign in as the victim. The callback now requires a short-lived state value bound to the user. Fixed by #39642 / #39744. Thanks to @cyberlanc3r and @u2usvc for reporting the issue, and to @SHIVANSHGARG07 and @wxiaoguang for the patch.
CVE-2026-107686: The web UI accepted reactions on locked issues and comments from users without write access, although the API refused them. Editing, deleting and reacting to issue content and comment attachments now share one permission check in the web UI and the API. Fixed by #39839 / #39847. Thanks to @hariprasanth9317-tech for reporting the issue, and to @silverwind, @wxiaoguang and @bircni for the patch.
CVE-2026-110494: Adding attachments to a release did not reject attachments that were already linked to an issue or comment, so a user with release write access could expose the metadata of an issue attachment through a release and then rename or delete it. Fixed by #39839 / #39847. Thanks to @manus-pi for reporting the issue, and to @silverwind, @wxiaoguang and @bircni for the patch.
CVE-2026-105661: Requesting /{username}/-/repositories for an individual user instead of an organization caused a nil-pointer panic, so anonymous visitors could trigger errors on every request. The route now returns 404 for individual users. Fixed by #39839 / #39847. Thanks to @kewmine, @tienpa99 and @gemstone-source for reporting the issue, and to @silverwind, @wxiaoguang and @bircni for the patch.
CVE-2026-110311: Creating a draft release returned the attachments of the whole instance, including issue and comment attachments of repositories the caller could not read. Fixed by #39743 / #39752. Thanks to @danielroe for reporting the issue, and to @wxiaoguang for the patch.
CVE-2026-105964: The Actions artifact v4 API read the request body without a size limit, so a holder of a runner token could exhaust the memory of the server. The body is now limited to 1 MiB. Fixed by #39818 / #39822. Thanks to @manus-pi and @N0K0 for reporting the issue, and to @SHIVANSHGARG07 for the patch.
CVE-2026-110324: Sending a POST request to the profile of a private or limited user returned profile information to users who could not see that profile. This was fixed in 28.1.0 and is disclosed with this release. Fixed by #39501 / #39507. Thanks to @Yanni8 for the analysis, and to @silverwind and @bircni for the patch.
CVE-2026-109844: GET /api/v1/user/subscriptions returned metadata of watched private repositories after the user had lost access to them. This was fixed in 28.0.0 and 1.27.0 and is disclosed with this release. Fixed by #38321 / #38390. Thanks to @manus-pi for reporting the issue, and to @bircni for the patch.
CVE-2026-107618: The repository topics endpoint was not covered by the cross-origin protection, so a third-party site could change the topics of a repository on behalf of a repository administrator (CSRF). Fixed by #39839 / #39847. Thanks to @bruhdev1290 for reporting the issue, and to @silverwind, @wxiaoguang and @bircni for the patch.
CVE-2026-97859: Seven API routes under /api/v1/users/{username} (followers, following, starred and watched repositories, SSH and GPG keys) were missing the visibility check, so an authenticated user could read them for users with limited or private visibility. This was fixed in 28.0.0 and 1.27.3 and is disclosed with this release. Fixed by #39004 / #39039. Thanks to @lukegranto23, @KadirArslan, @DshtAnger, @DevNoScope, @gigioneggiando and @manus-pi for reporting the issue, and to @bircni for the patch.
CVE-2026-97204: Deleting a label compared the repository ID against the organization ID of organization labels, so a user with write access to a repository could delete the labels of an organization with the same numeric ID. Labels are now deleted only within their own repository or organization. Fixed by #39743 / #39752. Thanks to @N0K0 for reporting the issue, and to @wxiaoguang for the patch.
We are grateful to all the security researchers who responsibly disclosed these issues.
Incoming email tokens of users who cannot sign in (inactive, prohibited or organizations) are rejected (#39833), competing remember-me token rotations no longer log users out (#39686), and WebAuthn accepts unsolicited client extension outputs from WebKit clients (#39792).
A commit with an empty author email is no longer matched to a user (#39777), email address validation is relaxed to what Go’s mail.ParseAddress accepts (#39661), and OIDC discovery no longer advertises an unsupported id_token response type (#39498).
The gitea-vscode OAuth2 application is pre-registered (#39785), and users with “Only Email on Mention” still receive emails for the events of a custom repository watch (#39652).
Folded block scalars in workflow files are kept intact (#39787), invalid activity type patterns no longer panic event detection (#39721), and out-of-range log cursors and unknown actor filters return proper errors instead of a 500 (#39721).
Schedules are cleaned up correctly and follow a default branch switch (#39740), and cancelled reusable workflow runs no longer get stuck in “cancelling” (#39706).
Pull requests whose recorded merge commit never reached the base repository are recovered (#39831), and empty pull requests are not detected as manually merged (#39807).
Review comments on unchanged lines show the correct code context (#39799), and file names with non-ASCII characters are shown correctly in the diff file tree (#39781).
Fetching remote commits skips writing the commit graph (#39798), reflog expiry is left to Git’s defaults (#39703), Git config values are matched exactly when syncing (#39728), and LFS object IDs are validated before they are turned into file system paths (#39762).
The go get URL uses the correct SSH scheme (#39674), and the issue branch/tag dropdown can select a tag again (#39747).
The former npm tarball URLs work again (#39681), and the Debian installation values can be copied (#39718).
srcset links of <source> elements are resolved and proxied (#39708), copying code from rendered blocks works again (#39755), and display MathML has the correct spacing (#39663).
Telegram webhook messages keep their line breaks (#39650), the milestone page uses the correct template variable (#39834), the change password page gets its websocket notification (#39671), and a panic in the notification service no longer crashes Gitea (#39835).
Download our pre-built binaries from the Gitea downloads page — make sure to select the version compatible with your platform. For a step-by-step guide on installation or upgrades, check out our installation documentation.
We would also like to thank all of our supporters on Open Collective who are helping to sustain us financially.
Looking for a seamless, hassle-free solution to manage your Git repositories?
Discover Gitea Cloud — A fully-managed, scalable platform designed to streamline your development workflow.