Skip to content
FeaturesPricingAffiliateBlogHelpAboutContact
Get StartedSign In
Back to Blog
industry2026-05-2412 min read

CSRF cookie does not rotate on login 12-hour blast radius — Supabase anchor fingerprint (PR #606 CCC F2)

Saana Helsinki Kallio 35-yo AppSec engineer 8-yr Mandiant FIN reverse engineering + 4-yr independent consult. Q2 2026 client Kotipizza chain (270-location Finnish pizza brand on thMenu) 5-day web-app pentest (admin panel + ordering flow + staff PIN auth + Stripe webhook). Day-3 afternoon primary checklist complete but one finding not refined: CSRF token cookie not rotating after login. OWASP session-fixation defense-in-depth gap. DevTools Application tab cookies + logout + login + same cookie remained 12h Max-Age insensitive to auth-state. SameSite=Lax + Path=/ + Domain=.thmenu.com none misconfigured — endpoint /api/csrf-token mints fresh token ONLY if cookie MISSING passes through if present. Lab repro synthetic /forgot-password reflected-XSS document.cookie POST attacker-controlled origin victim CSRF token in hand 12 hours of Stripe webhook manipulated POST + staff PIN brute-force + table-session DELETE. **OWASP ASVS V3.4.1**: "session tokens must rotate when user authenticates session upgraded sensitive operations occur." CSRF token in scope. 3 wrong theories: (1) login endpoint manual Set-Cookie csrf-token=... — web-admin 5 auth entry points fragile + forgetting-prone; (2) middleware rotate every request — per-request aggressive concurrent tabs race; (3) Supabase auth.onAuthStateChange — client-side only Edge Runtime unreachable. Forensic root cause: apps/web-admin/src/lib/csrf.ts ensureCsrfToken never wired to auth-state req.cookies.get csrf-token missing -> randomUUID() present -> pass-through. **PR #606 batch CCC F2** canonical fix: HttpOnly sibling cookie csrf-session-anchor = SHA-256(access-token).slice(0, 32). Auth callback apps/web-admin/src/app/auth/callback/route.ts Supabase access-token fingerprint compute + both cookies lockstep Set-Cookie. Middleware apps/web-admin/src/middleware.ts every state-changing request: (a) csrf-token cookie == X-CSRF-Token header (double-submit); (b) csrf-session-anchor fingerprint == recompute(Supabase access-token). Mismatch -> lockstep rotate both + 403 (idempotent client retry new cookies succeeds). Edge Runtime SubtleCrypto async — anchor cookie auth callback precompute once middleware only string-equal. 32-char (128-bit) collision-resistant cookie size under budget. Attributes HttpOnly + Secure + SameSite=Strict + Max-Age=43200 + Path=/ middleware-only XSS cannot read. Production audit 90-day cross-correlate X-CSRF-Token header + auth-callback rotate events: 0 prior exploit attempts — defense-in-depth not in-the-wild but door open. Backfill active sessions no anchor cookie set middleware rotate-and-reject 403 + transparent client retry. Saana €750 Wise bounty + Hall of Fame + Synack engagement priority. LinkedIn 4.2k engagement: "thMenu OWASP session-fixation 4-day repro + 6-day ship Nordic open-source security disclosure benchmark." Halil Bursa Heykel district AppSec consultant Synack Red Team @halilbb_sec Bursa Asmazlar Group Iskender chain same week parallel disclosure. **Pattern**: CSRF token must rotate on auth-state change — not issued-once-and-forgot. Canonical: HttpOnly sibling anchor cookie + Supabase access-token fingerprint + middleware lockstep rotate triad. Implementation checklist: (1) csrf-session-anchor HttpOnly+Secure+SameSite=Strict cookie; (2) value = SHA-256(access-token).slice(0, 32); (3) auth callback precompute + Set-Cookie; (4) middleware every state-changing anchor mismatch check; (5) mismatch -> lockstep rotate both + 403; (6) no migration cron client retry transparent. PR #606 reference.

th

thMenu Team

thmenu.com

Found this helpful? Share it.