Skip to content

Review CSRF protection for browser form actions

Map cookie-authenticated mutations to their CSRF controls. Test missing tokens, untrusted origins, and legitimate forms without changing real customer data.

Begin a CSRF review with the operations that change server state. Include profile changes, invitations, notification settings, and account recovery steps. A form that looks read-only can still submit a mutation through an unexpected route. Use synthetic records so the review does not alter a customer's account.

OWASP's CSRF guidance describes token-based controls and the limits of SameSite cookies. Prefer the framework's supported protection, then verify that each relevant handler actually uses it.

Build a mutation map

Follow one successful request from the browser to the handler. Record the authentication mechanism separately from the CSRF mechanism. A valid session establishes identity; it does not establish that the user intended a cross-site submission.

OperationBrowser credentialCSRF enforcementHarmless test result
Change display nameSession cookieFramework token checkMissing token leaves name unchanged
Create test invitationSession cookieToken and origin policyUntrusted origin creates no invitation
API-key-only operationExplicit authorization headerSeparate caller analysisNo ambient cookie fallback

Add every alternate content type and older route that reaches the same operation. Do not infer that protection on the newest form covers an older endpoint.

Exercise the deny cases

For each cookie-authenticated mutation, record the exact method, content type, route, and configured CSRF defense. Keep the legitimate request as a positive control. For a token-based handler, test a missing token, invalid token, and token from another test session. For an Origin, Fetch Metadata, or custom-header defense, test a disallowed source or missing required header and the documented fallback for absent browser headers. Check stored state and queued work after each denial. An error page is insufficient if the mutation happened first.

Use a controlled second origin to submit an HTML form, not only a scripted fetch. Forms can send simple content types without a CORS preflight. If the handler accepts JSON, test whether it rejects a form-encoded or text/plain body before parsing a mutation. Add a same-site sibling origin when deployment uses subdomains: a SameSite cookie may still accompany that request even though the origin differs. The OWASP CSRF guidance covers simple requests and the limits of SameSite.

Finally, issue an allowed-looking GET to each state-changing route. It must not change state. Record the request class, credential behavior, response, and unchanged row or job state for every negative case. A passing defense on one route does not cover an alternate parser or method.

Resolve exceptions explicitly

A webhook should not acquire a browser CSRF token requirement merely because it uses POST. It needs its provider-specific authenticity checks. Conversely, a browser action should not be exempted because an unrelated webhook shares a route prefix.

Record each exemption with its caller, credential type, enforcement code, and owner. Recheck the map after middleware or framework upgrades. Close a defect only when the disallowed request has no side effect and the intended user journey still completes. Treat SameSite as a documented layer, not a substitute for understanding the handler.

Find the gaps before your next launch

Use the release checklist to identify changed security boundaries and missing evidence. Discuss the application paths you want reviewed before launch.

Sources

  1. OWASP Cross-Site Request Forgery Prevention Cheat SheetAccessed