Cross site request forgery (CSRF) Cookie
Bypassing SameSite cookie restrictions
SameSite is a browser security mechanism that determines when a website's cookies are included in requests originating from other websites.
SameSite provides partial protection against a variety of cross-site attacks (eg. CSRF), cross-site leaks, and CORS exploits.
Site context and origins:
TLD (Top level Domain)
.com, .netTLD +1 (Name of site)
eTLD (effective Top level Domain)
A Site vs an Origin
A Site encompasses multiple domain names.
An Origin includes only one URL (same scheme, domain, and port).
How SameSite works
SameSite lets browsers and website owners limit which cross-site requests, if any, should include specific cookies.
SameSite restriction values:
Strict
Lax
None
Developers configure cookies in the Set-Cookie response header to include the SameSite attribute, e.g.:
Set-Cookie: session=0F8tgdOhi9ynR1M9wa3ODa; SameSite=Strict
Strict
Cookies are only sent if the browser is already on the same website.
Browser will not send it in cross-site requests.
If the target site request does not match the browser's address bar, do NOT include the cookie.
Prevents data modification via cross-site requests.
Lax
Cookies are sent only if you click a link that takes you to the website.
SameSite=Lax: browser will send the cookie for some cross-site requests if both conditions are met:
The request uses GET.
The request resulted from a top-level navigation (e.g., clicking a link).
Cookies are not included in cross-site POST requests.
None
Cookies are sent everywhere, even from other websites.
SameSite=None disables SameSite enforcement; requires Secure for HTTPS-only:
Set-Cookie: trackingId=0F8tgdOhi9ynR1M9wa3ODa; SameSite=None; Secure
Bypassing SameSite Lax restrictions using GET requests
Lab: SameSite Lax bypass via method override
Reconnaissance Plan
Login and change the email to observe the POST
/my-account/change-emailrequest.Capture the request via Burp; observe no CSRF tokens/unpredictable values.
Inspect cookies: no explicit SameSite attribute set — Chrome defaults to Lax.
In Burp Repeater, change the POST to GET to test whether a GET equivalent exists; server rejects plain GET (expects POST).
Attack
Use method override by adding
_method=POSTto the query string:
Example modified request: GET /my-account/change-email?email=foo@web-security-academy.net&_method=POST HTTP/1.1
Send this modified request (e.g., via Repeater). If the server honors
_method, it processes as a POST and updates the email.Confirm by visiting your account page in the browser.
Create an exploit on the exploit server that navigates the victim to that URL (top-level navigation so cookie is included).
Payload example:
Why the exploit works
SameSite=Lax loophole: Lax cookies are sent during top-level navigations (clicks/redirects). The exploit uses this to include the session cookie.
Method override: The
_methodparameter lets the server treat a GET as a POST, bypassing method-based protections.
Real-world analogy: a bank erroneously treats a GET-as-POST due to method-override; clicking a crafted link sends your session cookie and triggers a transfer.
Lab: SameSite Strict bypass via client-side redirect
Introduction
Scenario: After submitting a form, the site does a client-side (JavaScript) redirect. Cookies are set with SameSite=Strict, so they shouldn't be sent in cross-site requests. However, an attacker can manipulate the client-side redirect to load any URL on the bank's website. The internal jump from the confirmation page to the final URL includes the user's session cookie because the browser views it as same-site navigation.
Reconnaissance Plan
Login and observe the POST
/my-account/change-emailrequest; no CSRF tokens present.Observe server sets session cookie with SameSite=Strict.
Find a client-side redirect endpoint, e.g.
/post/comment/confirmation?postId=x, that reads postId and redirects topost/{postId}.Try path traversal in
postId(e.g.,1/../../my-account) and confirm navigation normalizes to/my-account.
Attack
Use the confirmation redirect gadget to navigate victims into a same-site context, then redirect again to the sensitive endpoint.
Example final URL (URL-encoding
&as%26):
/post/comment/confirmation?postId=1/../../my-account/change-email?email=pwned@web-security-academy.net%26submit=1
Host an exploit that navigates victims to that confirmation page; once the browser normalizes the redirect, it performs a same-site top-level navigation and includes Strict cookies.
Payload example:
Why the exploit works
Client-side redirect: JS redirects you from /post/comment/confirmation to a final path. Once you’re on the same domain, the navigation is same-site.
SameSite=Strict bypass: The second navigation is top-level same-site, so Strict cookies are included.
GET/Method override: The change-email endpoint accepts GET/method-override, so no CSRF token is required.
CSWSH (Cross-Site WebSocket Hijacking) via sibling-domain XSS
Lab: SameSite Strict bypass via sibling domain (CSWSH attack)
Full exploit (sibling-domain XSS)
Find a sibling domain (e.g.,
cms-LAB_ID.web-security-academy.net) that is treated as same-site.Discover a reflected XSS on that sibling (e.g., in
usernameparameter on login).Inject a URL-based XSS payload that runs the WebSocket extraction script in the sibling domain (same-site context). This lets the WebSocket handshake include the victim’s Strict session cookie and returns full chat history.
Example encoded redirect payload (place this in a page on your exploit server to navigate victim to the sibling login with encoded payload in username):
Final encoded payload example:
Why this works
SameSite=Strict cookies are included when requests originate from a same-site context. A sibling domain that is considered same-site will send those cookies.
The XSS on the sibling domain runs in the same-site context, allowing an authenticated WebSocket handshake.
The WebSocket connection accepts a trigger (e.g., "READY") that returns full chat history, exposing credentials without needing a collaborator.
Bypassing SameSite Lax restrictions with newly issued cookies (2-minute window)
What is SameSite=Lax?
Cookies with SameSite=Lax are not sent with cross-site POST requests.
They are sent with:
top-level GET requests (typing URL or clicking)
a first-time POST right after cookie creation (the 2-minute exception described below)
The 2-minute window (Chrome behavior)
Chrome applies SameSite=Lax by default when a cookie has no explicit SameSite attribute.
There is a 120-second exception: for up to 2 minutes after a cookie is (re)issued, the browser may allow cross-site POSTs to include that cookie.
This window can be exploited: force a victim to get a new cookie, then within 2 minutes send a cross-site POST to perform a CSRF.
How to trigger a new cookie
Force an SSO/OAuth login redirect or visit a login URL that refreshes the session.
This needs to happen without the browser blocking popups; user interaction (click) can be used to avoid popup blockers:
Example:
Steps summary:
1
Trigger new cookie (login/OAuth)
Starts 2-minute weak window
2
Use window.open() via a user click
Avoids popup blocker
3
Wait for new cookie
Browser sets new SameSite=Lax cookie
4
Send CSRF POST within 2 min
Cookie will be sent — attack succeeds
5
Cookie gets protected after 2 min
Window closes
Key brain hooks:
Cookies = VIP passes
SameSite=Lax = “Only use main door”
2-minute grace period = temporary weakness
New cookie = reset the timer
window.onclick = trick to open login without popup blocking
OAuth = reliable cookie refresher
Lab: SameSite Lax bypass via cookie refresh (OAuth flow)
Reconnaissance Plan
Login with OAuth and intercept POST
/my-account/change-emailin Burp. No CSRF token present.Note the session cookie is set without explicit SameSite — Chrome defaults to Lax.
/social-login(orGET /oauth-callback?code=...) refreshes the session cookie.Popup blockers prevent
window.openunless triggered by user interaction.
Vulnerability — Problem
Source: Session cookie is defaulted to Lax (no explicit SameSite=None/Strict).
Sink:
/my-account/change-emailaccepts cross-site POSTs if cookie is included.Challenges:
The 2-minute clock limits the window.
Popup blockers prevent automated opening of the OAuth flow without user action.
Why this works
Chrome allows session cookies set without SameSite explicitly to be used in cross-site POSTs for up to 2 minutes.
social-logintriggers a new session cookie, starting the 2-minute timer.window.onclickensures popup isn't blocked.Submitting after ~5 seconds means the POST occurs while the browser still includes the new cookie.
Last updated