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

CSRF Double Submit Cookie Pattern

security CWE-352 OWASP A1:2021 PHP 5.0+ Advanced
debt(d7/e5/b5/t7)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). Semgrep is listed in detection_hints.tools but automated detection is marked 'no'. Missing CSRF token checks or weak implementations (predictable tokens, missing SameSite) require manual security review or penetration testing to identify. No standard linter catches the subtle flaws like subdomain cookie attacks.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix recommends switching to synchroniser token pattern with session storage, which means adding session infrastructure, modifying all form handlers to generate/embed tokens, and updating validation logic across state-changing endpoints (POST/PUT/DELETE). Not a one-line fix, but contained to the auth/form handling layer.

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

Closest to 'persistent productivity tax' (b5). Applies only to web contexts, but CSRF protection is cross-cutting across all form handlers and state-changing endpoints. Once chosen, the double-submit pattern shapes how every form and AJAX request is built. Switching to synchroniser tokens later requires touching every protected endpoint. The architectural commitment affects multiple work streams but doesn't define the entire system.

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

Closest to 'serious trap' (t7). The misconception explicitly states developers believe double-submit is always safe, but subdomain takeover or XSS allows attackers to forge matching token pairs. This contradicts how developers expect stateless CSRF protection to work — they assume cookie matching is sufficient when it has a fundamental bypass. The common_mistakes reinforce multiple non-obvious failure modes.

About DEBT scoring →

Also Known As

double submit cookie stateless CSRF token

TL;DR

A stateless CSRF defence that sets a random cookie and requires it to also appear as a request parameter, relying on the Same-Origin Policy to prevent forgery.

Explanation

The double-submit cookie pattern is a stateless alternative to synchronised token pattern for CSRF protection. A cryptographically random value is set as a non-HttpOnly cookie; the client reads it via JavaScript and includes it in request headers or body parameters. The server verifies both values match. Because cross-origin requests cannot read cookies, an attacker cannot forge the matching pair. This pattern is suitable for SPAs but is undermined by subdomains that can set cookies on the parent domain — use the Signed Double-Submit Cookie variant to counter this.

Common Misconception

Double-submit cookie patterns are always safe from CSRF. If an attacker can write cookies on the target domain (via subdomain takeover or XSS), they can forge a matching token pair and bypass the check entirely.

Why It Matters

The double-submit cookie pattern validates a CSRF token by ensuring the cookie and form values match — without server-side session storage, it provides stateless CSRF protection.

Common Mistakes

  • Not using a cryptographically random token — a predictable cookie value is forgeable.
  • Subdomain cookie attacks: if attacker can write cookies for a subdomain, they can forge the double-submit.
  • Not using SameSite=Strict or Lax alongside double-submit — they are complementary defences.
  • Validating the token only on POST and not on other state-changing methods like PUT and DELETE.

Code Examples

✗ Vulnerable
// Predictable CSRF token — forgeable:
setcookie('csrf_token', md5(session_id())); // Predictable — session ID may be leaked

// Correct — random token:
$token = bin2hex(random_bytes(32));
setcookie('csrf_token', $token, ['samesite' => 'Strict', 'secure' => true]);
// Verify: $_POST['csrf_token'] === $_COOKIE['csrf_token']
✓ Fixed
// Double Submit Cookie — for stateless APIs that can't use server sessions

// 1. Server sets non-HttpOnly cookie (JS must read it)
setcookie('csrf_token', \$token = bin2hex(random_bytes(32)), [
    'path'     => '/',
    'secure'   => true,
    'httponly' => false,  // JS must be able to read this
    'samesite' => 'Strict',
]);

// 2. JS sends cookie value as a custom request header:
// fetch('/api/orders', {
//   method: 'POST',
//   headers: {'X-CSRF-Token': getCookie('csrf_token')},
// });

// 3. Server verifies header matches cookie:
\$cookie = \$_COOKIE['csrf_token'] ?? '';
\$header = \$_SERVER['HTTP_X_CSRF_TOKEN'] ?? '';
if (!hash_equals(\$cookie, \$header)) abort(403);
// Cross-site requests cannot read the cookie — so header can't be forged

Added 15 Mar 2026
Edited 22 Mar 2026
Views 28
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 1 ping S 2 pings S 0 pings M 0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 3 pings S 0 pings M 0 pings T 0 pings W 0 pings 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 1 ping S 2 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S
No pings yet today
No pings yesterday
Amazonbot 9 Perplexity 7 Google 2 Unknown AI 2 Ahrefs 2 ChatGPT 1
crawler 22 crawler_json 1
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Medium
⚡ Quick Fix
Use synchroniser token pattern: generate random_bytes(32) token in session, embed in forms, verify on every POST/PUT/DELETE
📦 Applies To
PHP 5.0+ web
🔗 Prerequisites
🔍 Detection Hints
Missing CSRF token check in form handlers; can be combined with SameSite=None cookies
Auto-detectable: ✗ No semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Medium ✗ Manual fix Fix: Medium Context: File Tests: Update
CWE-352

✓ schema.org compliant