skip to content

questions

4

A redelivery service's session cookie is SameSite=Lax; which cross-site forged requests still arrive carrying it?

level: middleimportance: must knowfreq 66%

answer

  1. one carve-out, not a wall
  2. the address bar changes, the cookie rides
  3. safe method plus top-level navigation
  4. state-changing GET is untouched
  5. safeness judged on the current hop

basics

~20 s

Lax withholds the cookie from cross-site subresource loads and cross-site form POSTs, but attaches it to cross-site top-level navigations using a safe method. Any state change reachable by GET therefore stays forgeable, including a POST a redirect converts into one.

solid answer

~40 s

`SameSite=Lax` splits cross-site traffic in two. A cross-site subresource load or a cross-site form POST gets no session cookie, so the hidden auto-submitting form is dead. A cross-site **top-level navigation** using a safe method — `GET`, `HEAD`, `OPTIONS`, `TRACE` — still carries it, because that carve-out is exactly what lets an inbound link from a notification message land the user signed in. So every endpoint that changes state on a `GET` is as forgeable as it was before: a hostile top-level document navigates to `https://redelivery.example/reschedule?parcel=...&slot=...` and the session cookie rides along. Safeness is judged on the redirect hop actually being made, so a cross-site `POST` that a `302 Found` turns into a `GET` arrives as a permitted navigation. Lax buys you the subresource and POST vectors, not GET.

code

html · 3 lines
html
<!-- served by the attacker as the TOP-LEVEL document, not inside a frame -->
<meta http-equiv="refresh"
      content="0; url=https://redelivery.example/reschedule?parcel=8812&slot=2026-09-22T09:00">

go deeper

for a junior

Remember the shape of the carve-out: a cross-site link that lands the user on your page still sends the session cookie, while a hidden cross-site form POST no longer does.

for a middle

Walk the three-part decision a client makes under Lax: is this request cross-site, is it a top-level navigation, and is its method safe? Only all three together attach the cookie.

for a senior

Show that you treat every state change reachable by a safe method as fully forgeable under Lax, and that you know safeness is evaluated on the redirect hop being made rather than on what the hostile document first emitted.

for a principal

The trade-off is entry-path usability against attack surface. Choosing Lax buys the inbound link and leaves a method-shaped hole, which moves the defence budget onto a check the server performs itself or onto splitting the session into read and write credentials.

## Why this service cannot use Strict People reach the parcel redelivery service by following a link out of a notification message, so the first request of nearly every session is a **cross-site top-level navigation**. `SameSite=Strict` would withhold the session cookie from precisely that navigation: the user taps the link they were told to tap and lands on the scheduling page signed out. `SameSite=Lax` exists for this shape of service. Once it is settled, the honest question is not what Lax protects but what it leaves forgeable. ## What Lax attaches, and what it withholds Under `SameSite=Lax` a conforming user agent attaches the cookie to: - every **same-site** request, of any method and any shape; - a **cross-site top-level navigation** whose method is safe in the `RFC 9110` sense — `GET`, `HEAD`, `OPTIONS`, `TRACE`. Everything else that is cross-site goes without it: | Cross-site request a hostile document can emit | Session cookie attached under Lax? | |---|---| | Image, script, stylesheet or frame subresource load | No | | Auto-submitting form POST (`application/x-www-form-urlencoded`, `multipart/form-data`, `text/plain`) | No | | Scripted call made in credentialed mode | No | | Top-level navigation using `GET` | **Yes** | | Top-level navigation using `POST` | No — except under a compatibility mode that applies only to cookies that set no `SameSite` attribute at all | The first two rows are the vectors most people picture when they hear "cross-site request forgery", and Lax genuinely removes them. That is real value, and it is why the attribute is worth setting. It is also the whole of what it buys. ## The gap: anything that changes state on a safe method The carve-out is **method-shaped**, not intent-shaped. The user agent has no idea whether `/reschedule?parcel=8812&slot=...` writes to a database; it sees a `GET`, sees a top-level navigation, and attaches the credential. A hostile page reaches that with ordinary markup — a `<meta http-equiv="refresh">` in the top-level document, or an anchor the victim is induced to click. The attacker never reads the response and does not need to: the redelivery slot has already moved. This is why an audit of a Lax-protected service is an audit of its **safe-method writes**. Endpoints spelled as a `GET` because they started life as a convenience link — cancel, confirm, unsubscribe, reschedule, a one-click action embedded in an email — sit entirely outside the attribute's protection, while the team believes a cookie attribute has covered them. ## Safeness is judged on the hop, not on what the page emitted The second half of the gap is subtler. A method may change across a redirect: a `POST` answered with `301 Moved Permanently` or `302 Found` is customarily reissued as a `GET`, while `307 Temporary Redirect` and `308 Permanent Redirect` preserve the method. Safeness is evaluated against **the request actually being made on the current hop**. So: 1. a hostile top-level document submits a form to a host the attacker controls; 2. that host answers `302 Found` with a `Location` pointing at `https://redelivery.example/reschedule?...`; 3. the hop the user agent now performs is a `GET` top-level navigation — safe, cross-site, therefore permitted; 4. the session cookie is attached. The exchange began as a cross-site `POST`, which Lax would have refused, and finished as something Lax allows. Reasoning about "the method the attacker used" rather than "the method on this hop" is the usual way this is missed. ## What the specification itself says `RFC 6265bis (draft-ietf-httpbis-rfc6265bis)` does not present Lax as a solution. Its own verdict is that Lax enforcement "does not offer a robust defense against CSRF as a general category of attack", and in its place it sketches a **two-cookie session design**: issue one read-only credential that is allowed to travel on cross-site requests, so the inbound link still renders a signed-in page, and a second read-write credential that is withheld from cross-site requests entirely, with every state-changing endpoint requiring the second. That splits the entry-path requirement away from the write path instead of trading one against the other. ## What to carry away SameSite is **defence in depth**. It narrows the set of documents that can spend your user's ambient authority; it does not remove the ambient authority, and the narrowing has a precise, method-shaped hole in it. The check that actually gates a state change is one the server performs on the request itself — a value it issued and can verify, or a comparison of where the request says it came from — and those are separate mechanisms with separate failure modes.

  • Why does a 302 Found on a cross-site POST matter to a Lax session cookie?
    Because the user agent judges safeness on the hop it is currently making. A POST answered with 301 or 302 is customarily reissued as a GET; that reissued request is a cross-site top-level navigation with a safe method, which Lax permits, so the cookie is attached. A 307 or 308 would have preserved the POST and the cookie would have stayed behind.
  • Our service has no state-changing GET endpoints. Does Lax then close the hole?
    No. Three gaps survive a clean method discipline: a host under the same registrable domain is same-site and gets the cookie regardless; a cookie that set no SameSite attribute at all can still ride a cross-site POST under a short compatibility window; and a client that does not implement the attribute ignores it outright. The attribute is not something the server can verify was honoured.
  • What session design does the cookie specification propose instead of a single Lax cookie?
    Two cookies for one session. A read-only credential that may travel on cross-site requests, so an inbound link still renders a signed-in page, and a read-write credential withheld from cross-site requests, which every state-changing endpoint requires. The entry path and the write path stop competing for one attribute value.

saying these in an interview costs you the question

  • Claims SameSite=Lax blocks every cross-site request
  • Treats a cross-site image load and a top-level navigation as the same case
  • Says a state-changing GET is safe because the cookie is Lax
  • Assumes a redirected POST is still judged as a POST
  • Believes Lax removes the need for any server-side check
  • Thinks the attacker must read the response for the forgery to succeed
open as a page

Your server sets SameSite=Lax on a session cookie — what can the server verify about whether that attribute was honoured?

level: juniorimportance: should knowfreq 56%

basics

~20 s

Nothing. SameSite is enforced entirely by the client; the server only writes the attribute into Set-Cookie. An arriving request carries an ordinary Cookie header that looks the same whether the client honoured the attribute or never implemented it at all.

open as a page

SameSite=Strict protects a redelivery session cookie; what does it stop from a compromised host under the same registrable domain?

level: seniorimportance: should knowfreq 44%

basics

~20 s

Nothing at all. Same-site is decided on the registrable domain, so any host beneath it is same-site with the service and its requests carry the session cookie in full, under Strict exactly as under Lax. SameSite is not a boundary between your own hosts.

open as a page

Why can a cookie sent with no SameSite attribute still ride a cross-site POST minutes after it was set?

level: seniorimportance: nice to knowfreq 28%

basics

~20 s

Because of a compatibility enforcement mode, not an attribute value. A user agent may treat a cookie that set no SameSite attribute as Lax while still allowing it on cross-site top-level requests with unsafe methods for a short period after creation; two minutes is cited as a reasonable limit.

open as a page