Skip to content

Conversation

@veeceey
Copy link

@veeceey veeceey commented Feb 10, 2026

Summary

Fixes #2874

When checkSecFetchSiteRequest() returns (true, nil) — e.g. for direct URL navigation where Sec-Fetch-Site: none, or same-origin requests — the CSRF middleware immediately calls return next(c) without:

  1. Generating or retrieving the CSRF token
  2. Setting the CSRF cookie
  3. Storing the token in context via c.Set(config.ContextKey, token)
  4. Adding the Vary: Cookie response header

This breaks all server-rendered forms that use c.Get("csrf") to embed a CSRF token in HTML for subsequent POST requests. The bug is triggered by every modern browser during direct navigation (typing a URL, clicking a bookmark, or following an external link), since browsers automatically send Sec-Fetch-Site: none in these scenarios.

Changes

  • middleware/csrf.go: Extract token generation and cookie/context setting into a setTokenInContext helper closure, and call it in the Sec-Fetch-Site allow path before calling next(c). The existing legacy token path remains unchanged.
  • middleware/csrf_test.go:
    • Add expectCookieContains assertion to the existing SecFetchSite=same-origin test case
    • Add two new table-driven test cases verifying cookie is set for Sec-Fetch-Site: none and same-origin GET requests
    • Add a dedicated TestCSRF_SecFetchSiteSetsTokenInContext regression test that verifies the token is accessible in context, the cookie is set, the Vary header is correct, and existing cookie tokens are reused

Test plan

  • All existing CSRF tests pass (go test ./middleware/ -run TestCSRF -v)
  • New regression tests pass for the exact scenario from the issue
  • Full test suite passes with race detector (go test -race ./...)
  • Verified the fix handles both new token generation and reuse of existing cookie tokens

🤖 Generated with Claude Code

…validation passes

When checkSecFetchSiteRequest() returned (true, nil) for requests with
Sec-Fetch-Site headers like "none" (direct navigation) or "same-origin",
the middleware called return next(c) without generating/retrieving the
CSRF token, setting the cookie, or storing the token in context. This
broke server-rendered forms that access the token via c.Get("csrf") to
embed it in HTML forms for subsequent POST requests.

Extract token generation and cookie/context setting into a helper
function and call it in the Sec-Fetch-Site allow path so that handlers
always have access to the CSRF token regardless of which validation
path was taken.

Fixes labstack#2874

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@aldas
Copy link
Contributor

aldas commented Feb 10, 2026

I though I had already merged #2894 I would prefer that solution. @veeceey would this work?

@veeceey
Copy link
Author

veeceey commented Feb 11, 2026

Thanks for the pointer! Yes, #2894 would work for this use case. I see that approach is more comprehensive since it handles the token generation in the success path of Sec-Fetch-Site check as well.

Happy to close this PR in favor of #2894 if you'd prefer to go with that solution. Let me know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CSRF middleware doesn't set token in context when Sec-Fetch-Site validation passes (v4.15.0)

2 participants