diff --git a/routers/web/web.go b/routers/web/web.go index 6cca2a9f2e..4dff09c846 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -177,7 +177,8 @@ func verifyAuthWithOptions(options *common.VerifyOptions) func(ctx *context.Cont return } - if !options.SignOutRequired && !options.DisableCSRF && ctx.Req.Method == "POST" { + safeMethod := ctx.Req.Method == "GET" || ctx.Req.Method == "HEAD" || ctx.Req.Method == "OPTIONS" + if !options.SignOutRequired && !options.DisableCSRF && !safeMethod { ctx.Csrf.Validate(ctx) if ctx.Written() { return diff --git a/tests/integration/csrf_test.go b/tests/integration/csrf_test.go index 100614cbb4..f548faeda6 100644 --- a/tests/integration/csrf_test.go +++ b/tests/integration/csrf_test.go @@ -1,4 +1,5 @@ // Copyright 2017 The Gitea Authors. All rights reserved. +// Copyright 2025 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package integration @@ -32,3 +33,23 @@ func TestCsrfProtection(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusBadRequest) assert.Contains(t, resp.Body.String(), "Invalid CSRF token") } + +func TestCSRFSafeMethods(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + t.Run("DELETE", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + session := loginUser(t, "user2") + resp := session.MakeRequest(t, NewRequest(t, "DELETE", "/user2/repo1/projects/1/2"), http.StatusBadRequest) + assert.Equal(t, "Invalid CSRF token.\n", resp.Body.String()) + }) + + t.Run("PUT", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + session := loginUser(t, "user2") + resp := session.MakeRequest(t, NewRequest(t, "PUT", "/user2/repo1/projects/1/2"), http.StatusBadRequest) + assert.Equal(t, "Invalid CSRF token.\n", resp.Body.String()) + }) +}