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

SameSite Lax Bypass

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

Closest to 'silent in production' (d8); owasp-zap and semgrep can flag GET-based state changes but won't reliably detect Lax-bypass scenarios — mostly requires manual review and threat modeling, so slightly better than d9.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5); quick_fix says to add CSRF tokens to state-changing requests and audit GET endpoints — this means refactoring routes (GET→POST), adding token middleware, and updating forms across the auth/action surface.

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

Closest to 'persistent productivity tax' (b5); applies to all web/api contexts and means every state-changing endpoint must be audited for method + CSRF token, shaping how routes and forms are written going forward.

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

Closest to 'serious trap' (t7); misconception explicitly states devs believe Lax is sufficient CSRF protection, which contradicts the reality that GET navigations, OAuth callbacks, and the Lax+POST window all bypass it — the 'obvious' defense is wrong in multiple documented ways.

About DEBT scoring →

Also Known As

SameSite Lax bypass cross-site GET attack

TL;DR

SameSite=Lax still sends cookies on top-level GET navigations — attackers can exploit this with GET-based state-changing endpoints.

Explanation

SameSite=Lax cookies are sent on cross-site top-level GET navigations (clicking a link, window.location redirect) but not on POST or iframe requests. This prevents classic CSRF but leaves a gap: if your application accepts state-changing GET requests (a logout link, a one-click delete, a token-based action URL), Lax doesn't protect them from CSRF. Additionally, some browsers apply a 2-minute 'Lax+POST' grace period for cookies without an explicit SameSite attribute — exploitable in some flows. Defences: use SameSite=Strict for sensitive session cookies where cross-site navigation isn't required; avoid state-changing GET endpoints; use CSRF tokens as a defence-in-depth layer even alongside SameSite.

Common Misconception

There is no practical way to bypass SameSite=Lax. GET-based state-changing endpoints, cross-site top-level navigation with redirects, and browser-specific quirks during the 2-minute "Lax+POST" window all represent documented Lax bypass scenarios.

Why It Matters

SameSite=Lax still sends cookies on top-level GET navigations — GET-based state-changing actions (logout via link, one-click actions) remain CSRF-vulnerable even with Lax protection.

Common Mistakes

  • Using SameSite=Lax as the sole CSRF defence without auditing GET-based state changes.
  • Login CSRF — if login itself is a GET (e.g. OAuth callback), Lax does not protect the session cookie.
  • Assuming Lax protects against all CSRF — Strict is needed for any sensitive GET-triggered actions.
  • Not combining SameSite with explicit CSRF tokens for high-security forms — defence in depth.

Code Examples

✗ Vulnerable
// GET-based logout — CSRF-able even with SameSite=Lax:
<a href="/logout">Logout</a>
// Attacker's page: <img src="https://victim.com/logout">
// Browser follows img src as top-level GET — Lax cookie sent — user logged out

// Fix: logout must be POST with CSRF token, not GET
✓ Fixed
// SameSite=Lax still sends cookies on top-level GET navigations
// Protect GET endpoints that change state:

// Bad: state-changing GET (bypasses SameSite=Lax)
// Route::get('/logout', [AuthController::class, 'logout']);

// Good: state changes via POST (SameSite=Lax blocks cross-site POST)
Route::post('/logout', [AuthController::class, 'logout']);

// Add CSRF token as an additional layer:
// <form method='POST'><input name='_token' value='{{ csrf_token() }}'>

// Highest security — use SameSite=Strict:
ini_set('session.cookie_samesite', 'Strict');
// Tradeoff: breaks auth on cross-site navigations (OAuth, email links)

Added 15 Mar 2026
Edited 22 Mar 2026
Views 19
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 1 ping F 0 pings S 1 ping S 0 pings M 0 pings T 1 ping W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 1 ping T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 1 ping T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F
No pings yet today
No pings yesterday
Amazonbot 7 Perplexity 4 Google 2 Ahrefs 1
crawler 13 crawler_json 1
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Medium
⚡ Quick Fix
Combine SameSite=Lax cookies with a CSRF token for state-changing requests — SameSite=Lax blocks cross-site POSTs but allows GET, so top-level navigation and some OAuth flows can still be exploited
📦 Applies To
PHP 7.3+ web api
🔗 Prerequisites
🔍 Detection Hints
Relying solely on SameSite=Lax as CSRF protection without synchronizer token; state-changing actions on GET endpoints
Auto-detectable: ✗ No owasp-zap semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: File Tests: Update
CWE-352

✓ schema.org compliant