CSRF in 2026
What still works and what died with Lax-by-default — the honest, browser-by-browser exploitability verdict, plus the techniques that are now purely historical.
The landscape changed, and most CSRF advice did not
Almost every CSRF tutorial still online was written before 2020. It teaches the auto-submitting cross-site POST form as the CSRF attack. In Chromium — the majority of the web — that exact attack has not worked by default since Chrome 80 shipped SameSite=Lax as the default for cookies with no SameSite attribute.
This has two consequences, and testers get burned by both:
- False negatives. You test the textbook POST form in Chrome, it fails, and you conclude the endpoint is protected. It is not — it may well be fully exploitable in Firefox and Safari, neither of which ever shipped a Lax default.
- False positives. You test in Firefox, it works, and you report "CSRF" without qualification. The triager tests in Chrome, sees nothing, and closes it.
The fix for both is the same: know which shape you are sending, know which cookie policy the target uses, and name the browsers in the finding. That is what this page is for.
The important structural point: CSRF did not die, it moved. The productive vectors in 2026 are top-level GET navigation, the endpoints that set SameSite=None because they needed third-party support, subdomain-adjacent attacks that SameSite never covered, and every non-cookie ambient credential.
Where the three engines actually stand
The live/dead ledger
The Lax+POST window, precisely
This is the most frequently misstated detail in modern CSRF write-ups, so it is worth being exact.
Chromium ships a temporary intervention: a cookie that has no SameSite attribute at all and was set less than 120 seconds ago is still sent on a cross-site top-level POST. The stated purpose is to avoid breaking POST-based SSO flows, where an identity provider sets a cookie and immediately POSTs back to the relying party.
What it does not do:
- It does not apply to a cookie explicitly marked
SameSite=Lax. An explicitLaxblocks a cross-site POST at any age. - It does not apply to subresource requests, only to top-level navigations.
- It is not guaranteed to stay. It has been documented as temporary since it shipped.
Practically: if you can get the victim to authenticate and then land on your page inside two minutes, an unset-SameSite cookie behaves the old way in Chromium too. Chaining a forced re-login makes this less theoretical than it sounds — see Bypassing SameSite.
What this means for testing
Work in this order. It is the reverse of the usual instinct, and it saves the most time.
- Read the
Set-Cookiefirst. Everything downstream depends on the session cookie'sSameSitevalue.Nonemeans the old rules apply almost everywhere. An absent attribute means you have a browser-dependent finding.Strictmeans you need a same-site gadget before anything else is worth trying. - Determine the auth mechanism. If it is a bearer token in a header, stop — there is no CSRF here. If it is Basic or a client certificate, SameSite is irrelevant and everything is live.
- Try GET first. If the endpoint accepts its state change over GET, you are done in every browser except
Strict. Check for method-override parameters too — see Method and Content-Type Switching. - Then the top-level POST form. Test it in Firefox as well as Chrome; they will disagree.
- Only then the exotic shapes —
text/plainJSON, subdomain cookie tossing, CORS assistance. - Write the finding with the browser named, the cookie's
SameSitevalue quoted from the response, and a PoC that a triager can open directly.
The PoC Generator applies all of this automatically: pick the delivery and the cookie policy and it tells you which engines will actually send the cookie.
Related
The browser attaches your credentials to any request an attacker can cause. The server sees a valid session and cannot tell who asked for it.
Exactly when Lax, Strict, None, and an absent attribute attach a cookie to a cross-site request — and why the three engines disagree.
Cookies are scoped by domain, not origin: who can set one, who receives one, and what __Host-, Secure, Path, and Partitioned actually change.
Lax top-level GET, Chromium's 120-second Lax+POST window, on-site redirect gadgets against Strict, and schemeful downgrade.
img, script, link, scripted link clicks, and top-level navigation — and why only the last one still carries a cookie.
Overwriting the CSRF cookie from a sibling subdomain, why SameSite offers zero protection here, and why __Host- is the fix.
Top-level form navigation reaches private addresses that Local Network Access does not gate, and Basic/NTLM/client-cert auth is ambient and SameSite-immune.
Enumerate, classify by auth mechanism, read the SameSite value first, then test — and write the finding with the browsers named.