← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Missing CSRF Protection

security PHP 5.0+ Intermediate
debt(d5/e3/b3/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5), because the detection_hints list semgrep and owasp-zap — both specialist SAST/DAST tools. A standard linter won't flag a missing middleware check; you need a dedicated security scanner or manual review to catch missing CSRF protection across routes.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3), because the quick_fix is 'Add CSRF middleware to all state-changing routes and verify the token on every POST/PUT/PATCH/DELETE request.' This is more than a one-line patch (it touches every state-changing route), but it is a repeatable pattern within one component/framework layer rather than a cross-cutting architectural refactor.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3), because applies_to is scoped to web contexts only and the fix is contained to route/middleware configuration. Once CSRF middleware is correctly wired in, it doesn't impose ongoing weight on most of the codebase; the burden is real but localised to the routing/middleware layer.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7), because the misconception field documents a genuine expert-level wrong belief: developers familiar with SameSite cookies believe they have replaced CSRF tokens, but SameSite=Lax still allows top-level navigation POSTs in some browsers. Additionally, common_mistakes include generating the token but never validating it (silent no-op) and only protecting forms but not AJAX endpoints — these are traps that contradict the intuition of developers who know a related concept (cookie security) but don't know the edge cases.

About DEBT scoring →

Also Known As

CSRF token missing no CSRF check cross-site request forgery

TL;DR

A state-changing form or endpoint that lacks a CSRF token allows attackers to forge authenticated requests from any website the victim visits.

Explanation

Cross-Site Request Forgery exploits the browser's automatic cookie sending — if a victim is logged in and visits a malicious page, that page can silently POST to your application using the victim's session. The fix is a synchronised token: generate a unique random value per session, embed it in every form as a hidden field, and validate it on every state-changing request. The token must be unpredictable, tied to the session, and verified server-side.

Common Misconception

SameSite cookies make CSRF tokens unnecessary — SameSite=Lax still allows top-level navigation POST in some browsers; SameSite=Strict alone is not universally sufficient. Always use tokens for critical actions.

Why It Matters

A missing CSRF token on a password-change or bank-transfer endpoint means any website the logged-in user visits can silently perform those actions on their behalf.

Common Mistakes

  • Checking Referer header instead of a token — Referer can be stripped by proxies and is not reliable.
  • Using the same CSRF token across multiple sessions — tokens must be unique per session.
  • Only protecting forms, not AJAX endpoints — JSON AJAX requests from a malicious site can also trigger CSRF.
  • Generating the token but never validating it server-side — silent no-op.

Code Examples

✗ Vulnerable
// No CSRF token — any site can forge this request:
<form method="POST" action="/change-password">
    <input name="password" type="password">
    <button type="submit">Change Password</button>
</form>

// PHP processes it without validation:
$_POST['password']; // Accepted from anywhere
✓ Fixed
// Generate token once per session:
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

// Embed in form:
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">

// Validate on every POST:
if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'] ?? '')) {
    http_response_code(403);
    exit('Invalid CSRF token');
}

Added 16 Mar 2026
Edited 22 Mar 2026
Views 34
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 0 pings F 0 pings S 2 pings S 2 pings M 0 pings T 2 pings W 1 ping T 0 pings F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 3 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F
No pings yesterday
Amazonbot 10 ChatGPT 6 Ahrefs 2 Google 2 Unknown AI 2 Perplexity 1 SEMrush 1
crawler 23 crawler_json 1
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Low
⚡ Quick Fix
Add CSRF middleware to all state-changing routes and verify the token on every POST/PUT/PATCH/DELETE request
📦 Applies To
PHP 5.0+ web laravel symfony
🔗 Prerequisites
🔍 Detection Hints
POST route handler missing VerifyCsrfToken middleware or manual token check
Auto-detectable: ✓ Yes semgrep owasp-zap
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Medium ✗ Manual fix Fix: Medium Context: File Tests: Update
CWE-352

✓ schema.org compliant