Cross-site request forgery (CSRF)

Methodology

Requirements for CSRF to Work

  • A relevant action must be possible (change username, email, password, etc.)

  • Cookie-based session handling

  • No unpredictable or unguessable request parameters


Case 1: Testing CSRF Tokens

  • Remove the CSRF token and see if the application still accepts the request.

  • Change the method from POST to GET.

  • Check if the CSRF token is tied to the user session.

  • Create a new CSRF token from one user and use it in another session.


Case 2: When CSRF Cookies Are Present

  • Check if the CSRF token is tied to the CSRF cookie.

  • Submit an invalid CSRF token.

  • Submit a valid CSRF token from another user.

  • Submit a valid CSRF token and CSRF cookie from another user.


Case 3: When Referer Header Is Used

  • Remove the Referer header.

  • Determine which part of the referer is being validated.

  • Attempt to bypass it by spoofing the required portion (see below).


Case 4: SameSite Cookies

  • Analyze SameSite settings: None, Lax, Strict.

  • Identify possible bypasses depending on configuration (see examples below).

PoC Examples

CSRF via GET

CSRF via POST

If the website contains any behavior that allows an attacker to set a cookie in a victim's browser, then an attack is possible. The attacker can log in to the application using their own account, obtain a valid token and associated cookie, leverage the cookie-setting behavior to place their cookie into the victim's browser, and feed their token to the victim in their CSRF attack.

Example:

Functionality that injects data into the headers
Injecting the csrfkey cookie into the headers

Referer techniques

CSRF + Removing referer Header

Bypassing Mandatory Referer (Old & Modern Techniques)

Old Technique: Use history.pushState() to spoof referer:

Modern Technique:

  • Use header Referrer-Policy: unsafe-url

  • Inject valid portion via URL if applicable

SameSite Protection Bypasses

Bypass SameSite=Lax via _method=POST

Some frameworks (Laravel, Symfony, Rails, etc.) support overriding HTTP methods via _method.

Original Request

Bypassed:

Bypass SameSite=Strict Using Gadgets

To exploit a SameSite=Strict cookie restriction, you can search for on-site gadgets—functionalities that allow you to trigger internal requests from within the same site. Common gadgets include:

  • Client-side redirects (JavaScript)

  • Dynamic links or anchor tags

  • Parameters that the frontend rewrites into internal URLs

  • XSS reflected or stored

These features are useful because browsers consider them same-site requests, meaning cookies will be included—even if the original interaction began from a cross-site context.

Exploitation Steps:

  1. Identify a gadget that reflects or redirects based on a user-controllable parameter (e.g., postId).

  2. Craft a malicious input that rewrites the target to an internal CSRF-sensitive endpoint. (change email)

  3. Trigger the gadget to make the browser issue the request from within the same site, causing it to include the session cookie.

This URL abuses a frontend gadget that rewrites the postId parameter into an internal request. By crafting the input, we force the application to issue a same-site request to /my-account/change-email, effectively bypassing the SameSite=Strict restriction and executing a CSRF attack.

POC for CSRF

Bypass SameSite=Lax Using Newly Issued Cookies (120s Window)

When a cookie is set without a SameSite attribute, Chrome applies SameSite=Lax by default. However, for the first 2 minutes, Chrome allows that cookie to be sent in cross-site POST requests, enabling a temporary CSRF window.

How to Identify:

  1. In Burp, find a Set-Cookie header that lacks a SameSite attribute. (/login)

  2. Confirm the cookie is used for session authentication.

  3. Verify a sensitive POST endpoint (e.g., /my-account/change-email) doesn't require CSRF tokens.

  4. Find a gadget like /social-login that triggers a new session cookie each time it's visited.

Exploitation Flow:

  1. Use window.open() to trigger /social-login → forces a new session cookie.

  2. Wait a few seconds.

  3. Auto-submit a CSRF POST form to the vulnerable endpoint using the fresh cookie.

Final Exploit Example:

Result: Chrome sends the new cookie in the POST request, bypassing SameSite=Lax.

Cross-Site WebSocket Hijacking

CSRF + XSS + Cross-Site WebSocket Hijacking (CSWSH)

Data urldecoded

The script was executed within the same origin. Since the malicious request was generated from JavaScript running on the legitimate domain, the browser included the SameSite=Strict cookie, allowing the attacker to:

  • Perform a full CSRF attack

  • Steal authenticated data from WebSocket messages

  • Exfiltrate the data to an attacker-controlled domain

Last updated