Code Review
A CSRF code review focuses on every state-changing request handler: does it require a token, a custom header, or mTLS? Are GET requests purely read-only? Are SameSite cookies set? Are CORS rules tight? This checklist turns it into a 15-minute pass per PR so CSRF bugs are caught before merge, not in a pen test.
CSRF review checklist with reviewable diffs
EXAMPLE
# CSRF code-review checklist (paste into the PR description)
## 1) Every state-changing route is POST/PUT/PATCH/DELETE
- [ ] No GET handler mutates state. Search for \\`Route::get\\` followed by writes.
## 2) Anti-CSRF token enforced on writes
- [ ] Laravel: route uses the 'web' middleware group (VerifyCsrfToken).
- [ ] Forms include \\`@csrf\\` (Blade) or send X-XSRF-TOKEN header.
- [ ] Same-origin XHR/fetch sends the cookie value back as a header.
## 3) Cookies are SameSite-protected
- [ ] config/session.php: 'same_site' => 'lax' (or 'strict' for high-risk apps).
- [ ] 'secure' => true in production.
## 4) CORS is opted in, not opt-out
- [ ] config/cors.php: 'paths' lists only the routes that need CORS.
- [ ] 'allowed_origins' is an explicit list, no '*'.
- [ ] 'supports_credentials' => true ONLY where required, and origin is exact.
## 5) Auth endpoints reject GET
- [ ] Login, password reset, OAuth callback only accept POST.
## 6) JSON APIs without cookies: custom required header
- [ ] Bearer-token APIs add a custom header (Authorization), so simple forms
cannot trigger a CSRF (browsers reject custom headers cross-origin).
# Example diff: harden a state-changing route
# BEFORE — bug
Route::get('/account/email', function (Request $request) {
$user = auth()->user();
$user->email = $request->query('to'); // ❌ GET that mutates
$user->save();
return 'ok';
});
# AFTER — fix
Route::post('/account/email', function (Request $request) {
$data = $request->validate(['to' => ['required','email']]);
$request->user()->update($data); // ✅ POST + token + validation
return response()->noContent();
})->middleware(['auth', 'verified']);
# Programmatic checks the reviewer can run
# 1) Find GETs that look mutating
git grep -n -E "Route::get\\(.*function" | grep -i -E 'update|delete|set|save|destroy'
# 2) Find disabled CSRF middleware
git grep -n 'VerifyCsrfToken' | grep -i 'except'
# 3) Confirm cookie config
grep -n 'same_site\|secure' config/session.php
Why it matters
A CSRF review takes 15 minutes per PR and catches a class of bugs that automated scanners often miss. The single highest-value check: search the diff for any new GET route that writes — those are the easy attacker wins.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
// Check every state-changing endpoint for: // - Method (must NOT be GET) // - CSRF token / custom-header check // - SameSite cookie config // - Origin/Referer validation for SSR formsTry it Yourself »
Discussion
Loading…