Red Team - Hard
Advanced CSRF Testing

Learn CSRF token bypass techniques, JSON endpoint CSRF, CVSS scoring for web vulnerabilities, and how to write a professional proof-of-concept finding report.

Hard Red Team Path ⏱ 26 min read
Learning Progress
0%

Advanced CSRF Testing

Hard-level CSRF testing goes beyond finding a missing token. It involves testing sophisticated application logic where protections may be bypassable or applied inconsistently, building working proof-of-concept exploits, and producing professional-grade reports including precise CVSS scoring and business impact assessment.

Many developers implement CSRF tokens believing they've fully addressed the risk — and many of those implementations have subtle flaws that render them ineffective. Advanced testing requires understanding how token validation works, not just whether a token field is present. The difference between a passing and a failing CSRF defence is often a single missing condition in a server-side validation check.

⚠️CVSS matters: CSRF on a funds transfer endpoint and CSRF on a comment form have very different severities. Accurate CVSS scoring communicates real risk — overscoring destroys credibility with clients, underscoring causes critical findings to be deprioritised.

Why Token-Protected Endpoints Are Still Testable

A CSRF token is only as strong as the validation logic that checks it. Token validation can fail in multiple independent ways — and each failure mode requires a different bypass technique. Understanding the complete validation chain is essential for hard-level testing.

The sealed envelope analogy: Imagine a mail room that checks for a security seal on every envelope before processing it. A naive implementation checks: "Is there a seal?" — but not "Is this the right seal for this sender?" or "Is the seal genuine?" An attacker who knows the rule "envelopes need a seal" can add any seal — even a fake one, even one they peeled off their own envelope — and the mail room will process it. CSRF token bypass works the same way: finding which part of the check is incomplete.

The correct validation chain for a CSRF token has four independent requirements, each of which must hold:

Most real-world bypass findings target the fourth condition — global token pools where any authenticated user's token is valid for any other user's session. This is by far the most common implementation error in mature applications that have "added CSRF protection."

📖The double-submit cookie pattern: Some applications use a double-submit pattern — a random value is set both as a cookie and as a request parameter, and the server checks they match. This is weaker than session-tied tokens: if an attacker can set a cookie on the target domain (via subdomain takeover or an XSS vulnerability), they can forge both the cookie and the parameter value and bypass the check entirely.

CSRF Bypass Techniques

Each bypass technique below targets a specific gap in common CSRF token validation logic. In a systematic assessment, all of these should be tested against every state-changing endpoint — not just the ones that appear unprotected at first glance.

Token Bypass Attack Vectors
Remove token       Delete csrf_token entirely -- does server validate presence?
Empty token        Send csrf_token= (blank) -- does server check non-empty?
Wrong token        Send another user's valid token -- is it session-tied?
Method change      POST with token -> GET without -- does GET change state?
Content-Type swap  application/json -> text/plain -- bypasses CORS preflight
Subdomain abuse    XSS on sub.corp.com can set cookies for corp.com
Header-only token  Token in custom header -- does endpoint also accept body param?
Predictable token  Sequential or timestamp-based token -- enumerate it

The method-change bypass deserves special attention. Some frameworks automatically route GET and POST to the same controller method, and the token validation middleware only fires for POST. By changing method="POST" to method="GET" and appending parameters to the URL, an attacker bypasses the token check entirely — the request is now a GET, which the middleware doesn't validate.

Advanced CSRF Testing in Practice

Example 01Mapping State-Changing Endpoints Systematically

Before attempting any bypass, a professional assessment systematically maps all state-changing endpoints and documents the token posture of each. This provides both a complete picture of the attack surface and the information needed to prioritise bypass attempts by potential impact. Burp's HTTP history is the starting point; every POST, PUT, DELETE, and PATCH request is a candidate.

# Document token status for every state-changing endpoint:
POST /account/change-email    -- has csrf_token: abc123   [LOW priority bypass]
POST /account/change-password -- has csrf_token: def456   [HIGH priority bypass]
POST /account/transfer-funds  -- NO csrf_token present    [CRITICAL — exploit directly]
POST /admin/create-user       -- has csrf_token: ghi789   [HIGH priority bypass]
DELETE /api/user/42           -- NO token, NO CORS header [CRITICAL — exploit directly]
# Prioritise: transfer-funds and DELETE /api/user are highest impact
# Test bypasses on: change-password and create-user (session-tied?)

The assessment matrix above gives you a triage order. No-token endpoints get PoC exploits first. Token-present endpoints get bypass testing in priority order by impact. Don't spend time bypassing a low-impact endpoint when a critical-impact unprotected endpoint is sitting right there.

Example 02Token Not Session-Tied — The Most Common Hard Bypass

The most frequently found bypass in applications that have implemented CSRF tokens: the server validates that the token exists and is a valid token, but doesn't verify it belongs to the current session. Any authenticated user's token is accepted for any other authenticated user's requests. The attacker obtains their own valid token, includes it in the forged request, and the server accepts it.

The wristband analogy: A concert venue gives every attendee a wristband at entry. Security checks wristbands at the VIP area — but they only check that the wristband is a real venue wristband, not that it belongs to the person wearing it. You can put on someone else's wristband (or hand yours to someone else) and get in. The check is real but incomplete. Token-not-session-tied validation is exactly this: the token is genuine, but it doesn't prove it was issued to you.

# Step 1: Log in as attacker, capture your own CSRF token from a form
csrf_token: ATTACKER_TOKEN_xyz789

# Step 2: Build PoC using YOUR token in the victim's forged request
<form action="https://bank.target.com/transfer" method="POST" id="csrf">
  <input type="hidden" name="amount" value="9999">
  <input type="hidden" name="to_account" value="ATTACKER_ACCOUNT">
  <input type="hidden" name="csrf_token" value="ATTACKER_TOKEN_xyz789">
</form>
<script>document.getElementById('csrf').submit();</script>

# Step 3: Victim visits page while logged in as their own account
# Server receives: victim's session cookie + attacker's CSRF token
# If transfer succeeds: token not session-tied → CONFIRMED BYPASS
Example 03JSON Endpoint CSRF via Content-Type Confusion

Modern API endpoints often use JSON for request bodies and omit CSRF tokens, assuming that the browser's CORS preflight mechanism protects them. The reasoning: JavaScript on another origin can't send Content-Type: application/json without triggering a CORS preflight, and the server would reject the preflight from an untrusted origin. But HTML forms are not JavaScript — and HTML forms can send text/plain without any preflight, no JavaScript required. If the server processes the request body regardless of the Content-Type header, the JSON CSRF is exploitable.

# Normal API call (protected by CORS preflight):
POST /api/transfer  Content-Type: application/json
{"amount":9999,"to_account":"attacker"}  ← requires preflight, blocked

# HTML form with text/plain — no preflight, browser sends freely:
<form action="https://api.target.com/transfer" method="POST"
      enctype="text/plain" id="csrf">
  <input name='{"amount":9999,"to_account":"ATTACKER"' value='"}'>
</form>
# Sends body: {"amount":9999,"to_account":"ATTACKER"}
# Content-Type: text/plain (no preflight)
# If server parses body regardless of Content-Type: exploitable

# Test: does the server return 200 vs 415 Unsupported Media Type?
# 200 with text/plain → server doesn't enforce Content-Type → exploitable

This technique catches developers who believed "JSON APIs are CSRF-safe." They are — when the server strictly enforces Content-Type: application/json. When the server processes whatever body it receives regardless of the header, the CORS-based protection evaporates.

Example 04CVSS Vector Calculation for CSRF Findings

CVSS scoring for CSRF findings must be calculated per-endpoint, because the same technical vulnerability (missing token) has wildly different impact depending on what the endpoint does. A pentest report that scores all CSRF findings identically is either overclaiming or underclaiming severity for most of them.

# CVSS v3.1 — CSRF on funds transfer endpoint:
Attack Vector: Network (N)         Complexity: Low (L)
Privileges Required: None (N)      User Interaction: Required (R)
Scope: Unchanged (U)
Confidentiality: None (N)          Integrity: High (H)     Availability: None (N)
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N → Base Score: 6.5 (MEDIUM)

# CVSS v3.1 — CSRF creating a new admin account (higher impact):
Confidentiality: High (H) — admin can read all data
Integrity: High (H)       — admin can modify anything
Availability: High (H)    — admin can delete/disrupt
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H → Base Score: 9.6 (CRITICAL)

# Same technical flaw. Two completely different business impacts.
# Client triage depends on accurate per-endpoint scoring.
Example 05Professional Finding Writeup Structure

A pentest-quality CSRF finding is not just a demonstration that the attack works — it provides everything a developer needs to understand the severity, reproduce it in their environment, understand the business impact, and implement a fix. Missing any component reduces the actionability of the report and the perceived credibility of the assessor.

Title       CSRF on /account/transfer-funds — unauthorised fund transfer
Severity    Medium (CVSS 6.5)
CVSS        CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N
CWE         CWE-352: Cross-Site Request Forgery
Affected    POST /account/transfer-funds (authenticated users)
Description The /transfer-funds endpoint accepts POST requests
            without a CSRF token, allowing any page visited by
            an authenticated user to silently initiate fund transfers.
Steps       1. Authenticate as victim (remain logged in)
            2. In a separate browser, visit attacker PoC [attached]
            3. Fund transfer of $9,999 executes automatically
            4. Victim receives no notification until statement review
Impact      Any authenticated user can have funds transferred to an
            attacker-controlled account by visiting a malicious link.
            Delivery vector: email, SMS, social media, forum post.
Fix         Implement synchronised CSRF tokens on all state-changing
            endpoints. Validate token presence, non-empty value, and
            session binding on every request. Supplement with
            SameSite=Strict on session cookies.

Advanced CSRF in Context

Scenario AThe Application That Added Tokens But Forgot One Endpoint

A financial services company completed a security remediation effort that added CSRF tokens to all form submissions following a prior pentest finding. A follow-up assessment six months later tests for CSRF again. All the original endpoints now have tokens — properly session-tied, properly validated. The assessor marks them as remediated.

However, during the assessment, a new feature was identified: a recently-added API endpoint POST /api/v2/beneficiary/add that adds a new payee to an account. This endpoint was built by a different team after the remediation effort and uses a JSON body with no CSRF token — the developer assumed "it's an API, CORS protects it." Testing with the text/plain Content-Type bypass confirms it's exploitable.

This pattern is extremely common. CSRF remediation on existing endpoints doesn't prevent new vulnerable endpoints from being introduced. Sustainable protection requires a framework-level CSRF middleware that applies by default to all routes, not per-endpoint opt-in protection.

Scenario BChaining CSRF with Subdomain XSS

A web application uses double-submit cookie CSRF protection — a random value is set as both a cookie and a form parameter, and the server checks they match. This is generally considered a reasonable protection. However, the organisation also runs a development subdomain, dev.corp.com, which has a stored XSS vulnerability in a comment field.

An attacker exploits the XSS on the dev subdomain to inject JavaScript that sets a new cookie on the parent domain (corp.com) — because cookies set by subdomains can apply to the parent domain depending on the cookie scope. The injected script sets the CSRF cookie to a known value, then submits a forged form with that same value as the parameter. The double-submit check passes — both values match — and the CSRF executes.

This chain demonstrates a critical architectural point: CSRF protection strength depends on the weakest point in the entire web estate. A vulnerability on any subdomain that can influence parent-domain cookies can break double-submit protection. The secure alternative — server-side session-tied tokens — is not vulnerable to this chain because the server controls what value is tied to a session, not the client.

🚨Lesson: Subdomain XSS + double-submit CSRF = full CSRF bypass. If your application uses double-submit cookies, every subdomain is part of your CSRF attack surface. This combination has been used in real bug bounty critical findings on major platforms.

Advanced CSRF and Organisational Risk

What You Need to Know

🎫
Token Validation Gaps
Presence of a token field is not protection. The server must: validate presence, check non-empty, verify the value is genuine, and confirm it's tied to the requesting session. All four, every time.
📝
CVSS Scoring
CSRF with High Integrity impact on sensitive functions scores 6.5 (Medium) to 9.6 (Critical) depending on Scope. Score per-endpoint — the same token absence has wildly different impact depending on what the endpoint does.
🌐
SameSite vs CSRF Tokens
SameSite=Strict/Lax prevents most CSRF at the browser level, but has edge cases (top-level navigation, GET-based state changes, pre-existing cookies). Session-tied CSRF tokens remain the recommended defence in depth.
📎
Working PoC Required
A working PoC HTML page is required for a credible hard-level finding. Without demonstrated exploitability, developers may dispute or deprioritise. The PoC should require no setup beyond opening the file while logged in.
🧵
Double-Submit Cookie Weakness
Double-submit cookie pattern is breakable via subdomain XSS — an attacker who can set a cookie on any subdomain can forge both the cookie and parameter to match. Session-tied tokens on the server are not vulnerable to this.
📦
Content-Type CORS Bypass
CORS preflight only fires for non-simple requests. HTML forms with enctype=text/plain bypass preflight entirely, allowing JSON-body forgery against endpoints that don't enforce Content-Type strictly.
Ready to put it into practice?
Proceed to the Lab

You've covered the theory. Now apply it hands-on in the simulated environment.

Start Lab — CSRF Hard
← Return to all labs