CVE-2021-45327
Description
Gitea before 1.11.2 is affected by Trusting HTTP Permission Methods on the Server Side when referencing the vulnerable admin or user API. which could let a remote malisious user execute arbitrary code.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Gitea before v1.11.2 trusts HTTP GET requests for admin/user API actions, allowing a remote attacker to execute arbitrary code.
Vulnerability
Gitea versions before 1.11.2 are affected by a vulnerability in the admin and user API endpoints that trust HTTP GET methods for operations that should require a POST request. This issue, identified as CVE-2021-45327 in references [1], allows a remote attacker to trigger server-side operations, including administrative actions, through simple GET requests [1][2][4]. The vulnerable endpoints include the admin dashboard operations, as shown by the commit that changed these GET-based actions to POST [2]. All Gitea instances running versions prior to 1.11.2 are affected [1].
Exploitation
An attacker with network access to the Gitea instance can exploit this by sending crafted HTTP GET requests to vulnerable admin or user API endpoints [1]. No authentication or special privileges are required if the attacker is able to reach the server over the network. The commit history shows that actions such as runOp were previously handled via GET, and the fix changed them to POST to require CSRF protection and proper HTTP method enforcement [2][4]. An attacker could chain these GET requests to trigger operations like user creation, repository deletion, or other administrative functions.
Impact
Successful exploitation allows a remote, unauthenticated attacker to execute arbitrary code on the Gitea server [1]. The vulnerable API endpoints may allow the attacker to perform privileged actions without proper authorization. This can lead to complete compromise of the Gitea instance, including data disclosure, file modification, and denial of service. The CVSS score for this CVE is not yet provided by NVD, but the impact is severe due to the potential for remote code execution in the admin context [1].
Mitigation
The vulnerability is fixed in Gitea version 1.11.2 [1][2]. The fix involved changing the HTTP methods for admin dashboard operations from GET to POST, as documented in pull request #10462 and commit ed664a9e1dae4d4660e60c981173bbc5102e69ea [2][4]. Users should upgrade to Gitea 1.11.2 or later immediately. No workaround is available for older versions. There is no indication that this CVE is listed in CISA's Known Exploited Vulnerabilities (KEV) catalog.
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/go-gitea/giteaGo | < 1.11.2 | 1.11.2 |
Affected products
3- Gitea/Giteadescription
- osv-coords2 versions
< 1.11.2+ 1 more
- (no CPE)range: < 1.11.2
- (no CPE)range: < 1.11.2
Patches
36f5656ab0ebeLogout POST action (#10582) (#10585)
4 files changed · +6 −3
integrations/signout_test.go+1 −1 modified@@ -14,7 +14,7 @@ func TestSignOut(t *testing.T) { session := loginUser(t, "user2") - req := NewRequest(t, "GET", "/user/logout") + req := NewRequest(t, "POST", "/user/logout") session.MakeRequest(t, req, http.StatusFound) // try to view a private repo, should fail
routers/routes/routes.go+1 −1 modified@@ -399,7 +399,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/recover_account", user.ResetPasswdPost) m.Get("/forgot_password", user.ForgotPasswd) m.Post("/forgot_password", user.ForgotPasswdPost) - m.Get("/logout", user.SignOut) + m.Post("/logout", user.SignOut) }) // ***** END: User *****
templates/base/head_navbar.tmpl+1 −1 modified@@ -109,7 +109,7 @@ {{end}} <div class="divider"></div> - <a class="item" href="{{AppSubUrl}}/user/logout"> + <a class="item link-action" href data-url="{{AppSubUrl}}/user/logout" data-redirect="{{AppSubUrl}}/"> <i class="octicon octicon-sign-out"></i> {{.i18n.Tr "sign_out"}}<!-- Sign Out --> </a>
web_src/js/index.js+3 −0 modified@@ -2740,11 +2740,14 @@ function showAddAllPopup() { function linkAction() { const $this = $(this); + const redirect = $this.data('redirect'); $.post($this.data('url'), { _csrf: csrf }).done((data) => { if (data.redirect) { window.location.href = data.redirect; + } else if (redirect) { + window.location.href = redirect; } else { window.location.reload(); }
ed664a9e1daeChange admin dashboard to POST (#10465) (#10466)
5 files changed · +81 −55
modules/auth/admin.go+10 −0 modified@@ -47,3 +47,13 @@ type AdminEditUserForm struct { func (f *AdminEditUserForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { return validate(errs, ctx.Data, f, ctx.Locale) } + +// AdminDashboardForm form for admin dashboard operations +type AdminDashboardForm struct { + Op int `binding:"required"` +} + +// Validate validates form fields +func (f *AdminDashboardForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { + return validate(errs, ctx.Data, f, ctx.Locale) +}
routers/admin/admin.go+19 −11 modified@@ -16,6 +16,7 @@ import ( "time" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/cron" @@ -30,7 +31,6 @@ import ( "gitea.com/macaron/macaron" "gitea.com/macaron/session" - "github.com/unknwon/com" ) const ( @@ -144,14 +144,28 @@ func Dashboard(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("admin.dashboard") ctx.Data["PageIsAdmin"] = true ctx.Data["PageIsAdminDashboard"] = true + ctx.Data["Stats"] = models.GetStatistic() + // FIXME: update periodically + updateSystemStatus() + ctx.Data["SysStatus"] = sysStatus + ctx.HTML(200, tplDashboard) +} + +// DashboardPost run an admin operation +func DashboardPost(ctx *context.Context, form auth.AdminDashboardForm) { + ctx.Data["Title"] = ctx.Tr("admin.dashboard") + ctx.Data["PageIsAdmin"] = true + ctx.Data["PageIsAdminDashboard"] = true + ctx.Data["Stats"] = models.GetStatistic() + updateSystemStatus() + ctx.Data["SysStatus"] = sysStatus // Run operation. - op, _ := com.StrTo(ctx.Query("op")).Int() - if op > 0 { + if form.Op > 0 { var err error var success string - switch Operation(op) { + switch Operation(form.Op) { case cleanInactivateUser: success = ctx.Tr("admin.dashboard.delete_inactivate_accounts_success") err = models.DeleteInactivateUsers() @@ -189,15 +203,9 @@ func Dashboard(ctx *context.Context) { } else { ctx.Flash.Success(success) } - ctx.Redirect(setting.AppSubURL + "/admin") - return } - ctx.Data["Stats"] = models.GetStatistic() - // FIXME: update periodically - updateSystemStatus() - ctx.Data["SysStatus"] = sysStatus - ctx.HTML(200, tplDashboard) + ctx.Redirect(setting.AppSubURL + "/admin") } // SendTestMail send test mail to confirm mail service is OK
routers/routes/routes.go+1 −0 modified@@ -408,6 +408,7 @@ func RegisterRoutes(m *macaron.Macaron) { // ***** START: Admin ***** m.Group("/admin", func() { m.Get("", adminReq, admin.Dashboard) + m.Post("", adminReq, bindIgnErr(auth.AdminDashboardForm{}), admin.DashboardPost) m.Get("/config", admin.Config) m.Post("/config/test_mail", admin.SendTestMail) m.Group("/monitor", func() {
templates/admin/dashboard.tmpl+47 −44 modified@@ -15,50 +15,53 @@ {{.i18n.Tr "admin.dashboard.operations"}} </h4> <div class="ui attached table segment"> - <table class="ui very basic table"> - <tbody> - <tr> - <td>{{.i18n.Tr "admin.dashboard.delete_inactivate_accounts"}}</td> - <td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=1">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td> - </tr> - <tr> - <td>{{.i18n.Tr "admin.dashboard.delete_repo_archives"}}</td> - <td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=2">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td> - </tr> - <tr> - <td>{{.i18n.Tr "admin.dashboard.delete_missing_repos"}}</td> - <td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=3">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td> - </tr> - <tr> - <td>{{.i18n.Tr "admin.dashboard.git_gc_repos"}}</td> - <td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=4">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td> - </tr> - <tr> - <td>{{.i18n.Tr "admin.dashboard.resync_all_sshkeys"}}</td> - <td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=5">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td> - </tr> - <tr> - <td>{{.i18n.Tr "admin.dashboard.resync_all_hooks"}}</td> - <td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=6">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td> - </tr> - <tr> - <td>{{.i18n.Tr "admin.dashboard.reinit_missing_repos"}}</td> - <td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=7">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td> - </tr> - <tr> - <td>{{.i18n.Tr "admin.dashboard.sync_external_users"}}</td> - <td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=8">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td> - </tr> - <tr> - <td>{{.i18n.Tr "admin.dashboard.git_fsck"}}</td> - <td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=9">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td> - </tr> - <tr> - <td>{{.i18n.Tr "admin.dashboard.delete_generated_repository_avatars"}}</td> - <td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=10">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td> - </tr> - </tbody> - </table> + <form method="post" action="{{AppSubUrl}}/admin"> + {{.CsrfTokenHtml}} + <table class="ui very basic table"> + <tbody> + <tr> + <td>{{.i18n.Tr "admin.dashboard.delete_inactivate_accounts"}}</td> + <td><button type="submit" class="ui green button" name="op" value="1"><i class="fa fa-caret-square-o-right"></i> {{.i18n.Tr "admin.dashboard.operation_run"}}</button></td> + </tr> + <tr> + <td>{{.i18n.Tr "admin.dashboard.delete_repo_archives"}}</td> + <td><button type="submit" class="ui green button" name="op" value="2"><i class="fa fa-caret-square-o-right"></i> {{.i18n.Tr "admin.dashboard.operation_run"}}</button></td> + </tr> + <tr> + <td>{{.i18n.Tr "admin.dashboard.delete_missing_repos"}}</td> + <td><button type="submit" class="ui green button" name="op" value="3"><i class="fa fa-caret-square-o-right"></i> {{.i18n.Tr "admin.dashboard.operation_run"}}</button></td> + </tr> + <tr> + <td>{{.i18n.Tr "admin.dashboard.git_gc_repos"}}</td> + <td><button type="submit" class="ui green button" name="op" value="4"><i class="fa fa-caret-square-o-right"></i> {{.i18n.Tr "admin.dashboard.operation_run"}}</button></td> + </tr> + <tr> + <td>{{.i18n.Tr "admin.dashboard.resync_all_sshkeys"}}</td> + <td><button type="submit" class="ui green button" name="op" value="5"><i class="fa fa-caret-square-o-right"></i> {{.i18n.Tr "admin.dashboard.operation_run"}}</button></td> + </tr> + <tr> + <td>{{.i18n.Tr "admin.dashboard.resync_all_hooks"}}</td> + <td><button type="submit" class="ui green button" name="op" value="6"><i class="fa fa-caret-square-o-right"></i> {{.i18n.Tr "admin.dashboard.operation_run"}}</button></td> + </tr> + <tr> + <td>{{.i18n.Tr "admin.dashboard.reinit_missing_repos"}}</td> + <td><button type="submit" class="ui green button" name="op" value="7"><i class="fa fa-caret-square-o-right"></i> {{.i18n.Tr "admin.dashboard.operation_run"}}</button></td> + </tr> + <tr> + <td>{{.i18n.Tr "admin.dashboard.sync_external_users"}}</td> + <td><button type="submit" class="ui green button" name="op" value="8"><i class="fa fa-caret-square-o-right"></i> {{.i18n.Tr "admin.dashboard.operation_run"}}</button></td> + </tr> + <tr> + <td>{{.i18n.Tr "admin.dashboard.git_fsck"}}</td> + <td><button type="submit" class="ui green button" name="op" value="9"><i class="fa fa-caret-square-o-right"></i> {{.i18n.Tr "admin.dashboard.operation_run"}}</button></td> + </tr> + <tr> + <td>{{.i18n.Tr "admin.dashboard.delete_generated_repository_avatars"}}</td> + <td><button type="submit" class="ui green button" name="op" value="10"><i class="fa fa-caret-square-o-right"></i> {{.i18n.Tr "admin.dashboard.operation_run"}}</button></td> + </tr> + </tbody> + </table> + </form> </div> <h4 class="ui top attached header">
web_src/less/_admin.less+4 −0 modified@@ -28,6 +28,10 @@ } } } + + form button[type='submit'] { + padding: 5px 8px; + } } .ui.header,
4cb18601ff33Change action GETs to POST (#10462) (#10464)
11 files changed · +79 −35
integrations/release_test.go+1 −1 modified@@ -20,7 +20,7 @@ func createNewRelease(t *testing.T, session *TestSession, repoURL, tag, title st resp := session.MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, resp.Body) - link, exists := htmlDoc.doc.Find("form").Attr("action") + link, exists := htmlDoc.doc.Find("form.ui.form").Attr("action") assert.True(t, exists, "The template has changed") postData := map[string]string{
routers/routes/routes.go+6 −6 modified@@ -485,7 +485,7 @@ func RegisterRoutes(m *macaron.Macaron) { }, reqSignIn) m.Group("/:username", func() { - m.Get("/action/:action", user.Action) + m.Post("/action/:action", user.Action) }, reqSignIn) if macaron.Env == macaron.DEV { @@ -517,16 +517,16 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/^:type(issues|pulls)$", user.Issues) m.Get("/milestones", reqMilestonesDashboardPageEnabled, user.Milestones) m.Get("/members", org.Members) - m.Get("/members/action/:action", org.MembersAction) + m.Post("/members/action/:action", org.MembersAction) m.Get("/teams", org.Teams) }, context.OrgAssignment(true)) m.Group("/:org", func() { m.Get("/teams/:team", org.TeamMembers) m.Get("/teams/:team/repositories", org.TeamRepositories) - m.Route("/teams/:team/action/:action", "GET,POST", org.TeamsAction) - m.Route("/teams/:team/action/repo/:action", "GET,POST", org.TeamsRepoAction) + m.Post("/teams/:team/action/:action", org.TeamsAction) + m.Post("/teams/:team/action/repo/:action", org.TeamsRepoAction) }, context.OrgAssignment(true, false, true)) m.Group("/:org", func() { @@ -660,7 +660,7 @@ func RegisterRoutes(m *macaron.Macaron) { }) }, reqSignIn, context.RepoAssignment(), context.UnitTypes(), reqRepoAdmin, context.RepoRef()) - m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), context.UnitTypes(), repo.Action) + m.Post("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), context.UnitTypes(), repo.Action) m.Group("/:username/:reponame", func() { m.Group("/issues", func() { @@ -714,7 +714,7 @@ func RegisterRoutes(m *macaron.Macaron) { Post(bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost) m.Get("/:id/edit", repo.EditMilestone) m.Post("/:id/edit", bindIgnErr(auth.CreateMilestoneForm{}), repo.EditMilestonePost) - m.Get("/:id/:action", repo.ChangeMilestonStatus) + m.Post("/:id/:action", repo.ChangeMilestonStatus) m.Post("/delete", repo.DeleteMilestone) }, context.RepoMustNotBeArchived(), reqRepoIssuesOrPullsWriter, context.RepoRef()) m.Group("/milestone", func() {
templates/org/member/members.tmpl+2 −2 modified@@ -22,10 +22,10 @@ {{ $isPublic := index $.MembersIsPublicMember .ID}} {{if $isPublic}} <strong>{{$.i18n.Tr "org.members.public"}}</strong> - {{if or (eq $.SignedUser.ID .ID) $.IsOrganizationOwner}}(<a href="{{$.OrgLink}}/members/action/private?uid={{.ID}}">{{$.i18n.Tr "org.members.public_helper"}}</a>){{end}} + {{if or (eq $.SignedUser.ID .ID) $.IsOrganizationOwner}}(<a class="link-action" href data-url="{{$.OrgLink}}/members/action/private?uid={{.ID}}">{{$.i18n.Tr "org.members.public_helper"}}</a>){{end}} {{else}} <strong>{{$.i18n.Tr "org.members.private"}}</strong> - {{if or (eq $.SignedUser.ID .ID) $.IsOrganizationOwner}}(<a href="{{$.OrgLink}}/members/action/public?uid={{.ID}}">{{$.i18n.Tr "org.members.private_helper"}}</a>){{end}} + {{if or (eq $.SignedUser.ID .ID) $.IsOrganizationOwner}}(<a class="link-action" href data-url="{{$.OrgLink}}/members/action/public?uid={{.ID}}">{{$.i18n.Tr "org.members.private_helper"}}</a>){{end}} {{end}} </div> </div>
templates/org/team/members.tmpl+4 −1 modified@@ -27,7 +27,10 @@ {{range .Team.Members}} <div class="item"> {{if $.IsOrganizationOwner}} - <a class="ui red small button right" href="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/remove?uid={{.ID}}">{{$.i18n.Tr "org.members.remove"}}</a> + <form method="post" action="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/remove?uid={{.ID}}"> + {{$.CsrfTokenHtml}} + <button type="submit" class="ui red small button right" >{{$.i18n.Tr "org.members.remove"}}</button> + </form> {{end}} <a href="{{.HomeLink}}"> <img class="ui avatar image" src="{{.RelAvatarLink}}">
templates/org/team/repositories.tmpl+4 −1 modified@@ -35,7 +35,10 @@ {{range .Team.Repos}} <div class="item"> {{if $canAddRemove}} - <a class="ui red small button right" href="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/repo/remove?repoid={{.ID}}">{{$.i18n.Tr "remove"}}</a> + <form method="post" action="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/repo/remove?repoid={{.ID}}"> + {{$.CsrfTokenHtml}} + <button type="submit" class="ui red small button right">{{$.i18n.Tr "remove"}}</button> + </form> {{end}} <a class="member" href="{{AppSubUrl}}/{{$.Org.Name}}/{{.Name}}"> <i class="octicon octicon-{{if .IsPrivate}}lock{{else if .IsFork}}repo-forked{{else if .IsMirror}}repo-clone{{else}}repo{{end}}"></i>
templates/org/team/sidebar.tmpl+8 −2 modified@@ -3,9 +3,15 @@ <strong>{{.Team.Name}}</strong> <div class="ui right"> {{if .Team.IsMember $.SignedUser.ID}} - <a class="ui red tiny button" href="{{.OrgLink}}/teams/{{.Team.LowerName}}/action/leave?uid={{$.SignedUser.ID}}&page=home">{{$.i18n.Tr "org.teams.leave"}}</a> + <form method="post" action="{{.OrgLink}}/teams/{{.Team.LowerName}}/action/leave?uid={{$.SignedUser.ID}}&page=home"> + {{$.CsrfTokenHtml}} + <button type="submit" class="ui red tiny button">{{$.i18n.Tr "org.teams.leave"}}</button> + </form> {{else if .IsOrganizationOwner}} - <a class="ui blue tiny button" href="{{.OrgLink}}/teams/{{.Team.LowerName}}/action/join?uid={{$.SignedUser.ID}}&page=team">{{$.i18n.Tr "org.teams.join"}}</a> + <form method="post" action="{{.OrgLink}}/teams/{{.Team.LowerName}}/action/join?uid={{$.SignedUser.ID}}&page=team"> + {{$.CsrfTokenHtml}} + <button type="submit" class="ui blue tiny button">{{$.i18n.Tr "org.teams.join"}}</button> + </form> {{end}} </div> </h4>
templates/org/team/teams.tmpl+8 −2 modified@@ -17,9 +17,15 @@ <a class="text black" href="{{$.OrgLink}}/teams/{{.LowerName}}"><strong>{{.Name}}</strong></a> <div class="ui right"> {{if .IsMember $.SignedUser.ID}} - <a class="ui red small button" href="{{$.OrgLink}}/teams/{{.LowerName}}/action/leave?uid={{$.SignedUser.ID}}">{{$.i18n.Tr "org.teams.leave"}}</a> + <form method="post" action="{{$.OrgLink}}/teams/{{.LowerName}}/action/leave?uid={{$.SignedUser.ID}}"> + {{$.CsrfTokenHtml}} + <button type="submit" class="ui red small button">{{$.i18n.Tr "org.teams.leave"}}</button> + </form> {{else if $.IsOrganizationOwner}} - <a class="ui blue small button" href="{{$.OrgLink}}/teams/{{.LowerName}}/action/join?uid={{$.SignedUser.ID}}">{{$.i18n.Tr "org.teams.join"}}</a> + <form method="post" action="{{$.OrgLink}}/teams/{{.LowerName}}/action/join?uid={{$.SignedUser.ID}}"> + {{$.CsrfTokenHtml}} + <button type="submit" class="ui blue small button">{{$.i18n.Tr "org.teams.join"}}</button> + </form> {{end}} </div> </div>
templates/repo/header.tmpl+22 −16 modified@@ -20,22 +20,28 @@ </div> {{if not .IsBeingCreated}} <div class="repo-buttons"> - <div class="ui labeled button" tabindex="0"> - <a class="ui compact basic button" href="{{$.RepoLink}}/action/{{if $.IsWatchingRepo}}un{{end}}watch?redirect_to={{$.Link}}"> - <i class="icon fa-eye{{if not $.IsWatchingRepo}}-slash{{end}}"></i>{{if $.IsWatchingRepo}}{{$.i18n.Tr "repo.unwatch"}}{{else}}{{$.i18n.Tr "repo.watch"}}{{end}} - </a> - <a class="ui basic label" href="{{.Link}}/watchers"> - {{.NumWatches}} - </a> - </div> - <div class="ui labeled button" tabindex="0"> - <a class="ui compact basic button" href="{{$.RepoLink}}/action/{{if $.IsStaringRepo}}un{{end}}star?redirect_to={{$.Link}}"> - <i class="icon star{{if not $.IsStaringRepo}} outline{{end}}"></i>{{if $.IsStaringRepo}}{{$.i18n.Tr "repo.unstar"}}{{else}}{{$.i18n.Tr "repo.star"}}{{end}} - </a> - <a class="ui basic label" href="{{.Link}}/stars"> - {{.NumStars}} - </a> - </div> + <form method="post" action="{{$.RepoLink}}/action/{{if $.IsWatchingRepo}}un{{end}}watch?redirect_to={{$.Link}}"> + {{$.CsrfTokenHtml}} + <div class="ui labeled button" tabindex="0"> + <button type="submit" class="ui compact basic button"> + <i class="icon fa-eye{{if not $.IsWatchingRepo}}-slash{{end}}"></i>{{if $.IsWatchingRepo}}{{$.i18n.Tr "repo.unwatch"}}{{else}}{{$.i18n.Tr "repo.watch"}}{{end}} + </button> + <a class="ui basic label" href="{{.Link}}/watchers"> + {{.NumWatches}} + </a> + </div> + </form> + <form method="post" action="{{$.RepoLink}}/action/{{if $.IsStaringRepo}}un{{end}}star?redirect_to={{$.Link}}"> + {{$.CsrfTokenHtml}} + <div class="ui labeled button" tabindex="0"> + <button type="submit" class="ui compact basic button"> + <i class="icon star{{if not $.IsStaringRepo}} outline{{end}}"></i>{{if $.IsStaringRepo}}{{$.i18n.Tr "repo.unstar"}}{{else}}{{$.i18n.Tr "repo.star"}}{{end}} + </button> + <a class="ui basic label" href="{{.Link}}/stars"> + {{.NumStars}} + </a> + </div> + </form> {{if and (not .IsEmpty) ($.Permission.CanRead $.UnitTypeCode)}} <div class="ui labeled button {{if and ($.IsSigned) (not $.CanSignedUserFork)}}disabled-repo-button{{end}}" tabindex="0"> <a class="ui compact basic button {{if or (not $.IsSigned) (not $.CanSignedUserFork)}}poping up{{end}}" {{if $.CanSignedUserFork}}href="{{AppSubUrl}}/repo/fork/{{.ID}}"{{else if $.IsSigned}} data-content="{{$.i18n.Tr "repo.fork_from_self"}}" {{ else }} data-content="{{$.i18n.Tr "repo.fork_guest_user" }}" rel="nofollow" href="{{AppSubUrl}}/user/login?redirect_to={{AppSubUrl}}/repo/fork/{{.ID}}" {{end}} data-position="top center" data-variation="tiny">
templates/repo/issue/milestones.tmpl+2 −2 modified@@ -71,9 +71,9 @@ <div class="ui right operate"> <a href="{{$.Link}}/{{.ID}}/edit" data-id={{.ID}} data-title={{.Name}}><i class="octicon octicon-pencil"></i> {{$.i18n.Tr "repo.issues.label_edit"}}</a> {{if .IsClosed}} - <a href="{{$.Link}}/{{.ID}}/open" data-id={{.ID}} data-title={{.Name}}><i class="octicon octicon-check"></i> {{$.i18n.Tr "repo.milestones.open"}}</a> + <a class="link-action" href data-url="{{$.Link}}/{{.ID}}/open" data-id={{.ID}} data-title={{.Name}}><i class="octicon octicon-check"></i> {{$.i18n.Tr "repo.milestones.open"}}</a> {{else}} - <a href="{{$.Link}}/{{.ID}}/close" data-id={{.ID}} data-title={{.Name}}><i class="octicon octicon-x"></i> {{$.i18n.Tr "repo.milestones.close"}}</a> + <a class="link-action" href data-url="{{$.Link}}/{{.ID}}/close" data-id={{.ID}} data-title={{.Name}}><i class="octicon octicon-x"></i> {{$.i18n.Tr "repo.milestones.close"}}</a> {{end}} <a class="delete-button" href="#" data-url="{{$.RepoLink}}/milestones/delete" data-id="{{.ID}}"><i class="octicon octicon-trashcan"></i> {{$.i18n.Tr "repo.issues.label_delete"}}</a> </div>
templates/user/profile.tmpl+8 −2 modified@@ -65,9 +65,15 @@ {{if and .IsSigned (ne .SignedUserName .Owner.Name)}} <li class="follow"> {{if .SignedUser.IsFollowing .Owner.ID}} - <a class="ui basic red button" href="{{.Link}}/action/unfollow?redirect_to={{$.Link}}"><i class="octicon octicon-person"></i> {{.i18n.Tr "user.unfollow"}}</a> + <form method="post" action="{{.Link}}/action/unfollow?redirect_to={{$.Link}}"> + {{$.CsrfTokenHtml}} + <button type="submit" class="ui basic red button"><i class="octicon octicon-person"></i> {{.i18n.Tr "user.unfollow"}}</button> + </form> {{else}} - <a class="ui basic green button" href="{{.Link}}/action/follow?redirect_to={{$.Link}}"><i class="octicon octicon-person"></i> {{.i18n.Tr "user.follow"}}</a> + <form method="post" action="{{.Link}}/action/follow?redirect_to={{$.Link}}"> + {{$.CsrfTokenHtml}} + <button type="submit" class="ui basic green button"><i class="octicon octicon-person"></i> {{.i18n.Tr "user.follow"}}</button> + </form> {{end}} </li> {{end}}
web_src/js/index.js+14 −0 modified@@ -2479,6 +2479,7 @@ $(document).ready(() => { // Helpers. $('.delete-button').click(showDeletePopup); $('.add-all-button').click(showAddAllPopup); + $('.link-action').click(linkAction); $('.delete-branch-button').click(showDeletePopup); @@ -2736,6 +2737,19 @@ function showAddAllPopup() { return false; } +function linkAction() { + const $this = $(this); + $.post($this.data('url'), { + _csrf: csrf + }).done((data) => { + if (data.redirect) { + window.location.href = data.redirect; + } else { + window.location.reload(); + } + }); +} + function initVueComponents() { const vueDelimeters = ['${', '}'];
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
10- github.com/advisories/GHSA-jrpg-35hw-m4p9ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2021-45327ghsaADVISORY
- blog.gitea.io/2020/03/gitea-1.11.2-is-releasedghsaWEB
- blog.gitea.io/2020/03/gitea-1.11.2-is-released/mitrex_refsource_MISC
- github.com/go-gitea/gitea/commit/4cb18601ff33dda5edb47d5b452cc8f2dc39dd67ghsaWEB
- github.com/go-gitea/gitea/commit/6f5656ab0ebec03fe63898208dabc802c4be46abghsaWEB
- github.com/go-gitea/gitea/commit/ed664a9e1dae4d4660e60c981173bbc5102e69eaghsaWEB
- github.com/go-gitea/gitea/pull/10462ghsax_refsource_MISCWEB
- github.com/go-gitea/gitea/pull/10465ghsax_refsource_MISCWEB
- github.com/go-gitea/gitea/pull/10582ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.