1

Detection

Identify state-changing endpoints

🔎

Detection

CSRF testing only matters against requests that can actually change server-side state, as established in what is csrf. The first step is therefore not to test every endpoint uniformly, but to build a complete inventory of the application's state-changing operations.

Walk through the application using an intercepting proxy such as Burp Suite or OWASP ZAP and perform every action available to the account.

Look for operations such as:

  • Profile updates.

  • Password changes.

  • Email changes.

  • MFA enrollment or removal.

  • Account recovery actions.

  • Purchases and payment changes.

  • Transfers or other financial operations.

  • Resource creation, modification, or deletion.

  • Settings and preference changes.

  • Role or permission changes.

  • Subscription changes or cancellations.

  • Logout.

  • Any other action that changes account or application state.

Flag requests using methods normally associated with state changes:

POST
PUT
PATCH
DELETE

Also explicitly look for GET requests with side effects.

GET /account/delete?confirm=true

GET /settings/enable-feature

GET /logout

As discussed in where CSRF vulnerabilities occur, a state-changing GET is particularly important because the request may be triggerable through nothing more than a navigation or resource load.

State-changing GET
        ↓
Potentially triggerable through:
<a href="...">
<img src="...">
iframe
Redirect
        ↓
High-priority CSRF test candidate

For each identified endpoint, record the relevant details:

Endpoint:    POST /api/account/email

Action:    Changes registered email address

Authentication required?
    Yes

State-changing?
    Yes

CSRF token present?
    Yes / No
Other apparent protections?
    SameSite
    Origin validation
    Custom header requirement
    Re-authentication
    Confirmation flow

The goal is to produce a map like this:

Application action
        ↓
Underlying request
        ↓
HTTP method
        ↓
Authentication requirement
        ↓
CSRF or request-integrity mechanism
        ↓
Test priority

An endpoint with no obvious CSRF token is often worth testing early, but the absence of a visible token is not itself proof of a vulnerability. The application may rely on another mechanism, such as:

  • SameSite cookie restrictions.

  • Origin or Referer validation.

  • A required custom request header that a cross-origin form cannot set.

  • Re-authentication.

  • Another server-side request-integrity control.

2

Detection

Remove CSRF token

🔎

Detection

The most basic CSRF validation test is to take a legitimate, captured state-changing request and resend it with the CSRF token removed entirely.

For example, suppose the original request contains:

For example, suppose the original request contains:

POST /api/account/password HTTP/1.1
Cookie: session=abc123def456
Content-Type: application/x-www-form-urlencoded

newPassword=changed123&csrf_token=a9f3e7c1b2d84f...

Remove only the token field:

POST /api/account/password HTTP/1.1
Cookie: session=abc123def456
Content-Type: application/x-www-form-urlencoded

newPassword=changed123
Legitimate request
        ↓
CSRF token removed
        ↓
Request replayed

If the server still processes the request and performs the state-changing action, the endpoint is not enforcing token presence at all.

Request contains:

Valid session cookie
        ✓
CSRF token:  Missing
        ↓
Server processes action anyway
        ↓
 CSRF protection has failed

This directly exposes the first validation weakness discussed in CSRF Token: the endpoint either performs no CSRF validation or has a validation path that allows the request to proceed without a token.

The next tests should determine whether:

✓ The submitted token must have the correct value

✓ The token is bound to the current session

✓ A token from another session is rejected

✓ Modified or attacker-generated values are rejected

✓ Validation is enforced consistently
  across equivalent endpoints and flows

3

Detection

Modify token

🔎

Detection

If the endpoint rejects a request with the CSRF token removed, the next question is whether it actually validates the token's value.

Take the same legitimate request and keep the token field present, but replace its value with something invalid.

For example:

POST /api/account/password HTTP/1.1
Cookie: session=abc123def456
Content-Type: application/x-www-form-urlencoded

newPassword=changed123&csrf_token=a9f3e7c1b2d84f...

Change one character:

POST /api/account/password HTTP/1.1
Cookie: session=abc123def456
Content-Type: application/x-www-form-urlencoded

newPassword=changed123&csrf_token=a9f3e7c1b2d84X...

Or truncate it:

csrf_token=a9f3e7c1

Or replace it with a completely arbitrary value:

csrf_token=this-is-not-a-valid-token

Then resend the request.

Legitimate request
        ↓
Token field remains present
        ↓
Token value is modified
        ↓
Request replayed

If the server accepts the request and performs the action despite the token being clearly invalid, the application has a serious validation failure.

It is worth testing more than one type of invalid value.

A CSRF token field provides no protection merely by existing. The server must verify that the submitted value is the correct value for the current request or session, using a strict validation path that fails closed. A token that is missing, modified, invented, expired, or borrowed from an unrelated session should not authorize a state-changing request.

4

Detection

Reuse token

🔎

Detection

The previous tests established whether the server validates the token's value. The next question is whether it manages the token's lifecycle correctly.

For applications using a per-session token, capture a valid token early in the session and continue using it in later legitimate requests.

Obtain valid token
        ↓
Use token successfully
        ↓
Perform additional actions
        ↓
Submit the same token again
        ↓
Does it remain valid?

For a genuine per-session implementation, continued validity is normally expected. The token is designed to remain associated with that session rather than being replaced after every request.

The important tests are therefore the points where the application claims or requires the token to change, such as an authentication boundary, session destruction, or another security-sensitive lifecycle event.

For example:

Valid CSRF token
        ↓
Login / session rotation
        ↓
Application issues new session
        ↓
Test whether the old token
is still accepted with the new session

If the application rotates the session at login, a CSRF token bound to the old session should not automatically become valid for the new session unless the application's design explicitly preserves that relationship.

For password changes or other security-sensitive transitions, test the behavior according to the application's documented token lifecycle. If the application claims to rotate or invalidate CSRF tokens at such an event, verify that the old value is actually rejected afterward.

Token Lifecycle:

Do not assume that every per-session token should expire independently of the session.

If the application documents a token lifetime, test it explicitly:

Capture valid token
        ↓
Wait beyond documented lifetime
        ↓
Reuse token
        ↓
Expected: Token rejected

Replaying a Per-Request Token:

For applications specifically designed to use per-request tokens, perform a different test.

Capture a valid token and use it once in a legitimate request:

Per-request token
        ↓
First legitimate request
        ↓
 Request succeeds
        ↓
Submit the exact same token again
        ↓
 Expected: request rejected

If the same token can be reused immediately and indefinitely, the implementation is not enforcing one-time use as designed.

If the second request succeeds, the implementation may be behaving more like a reusable session-lifetime token than a genuinely one-time token.

Per-session token:

Issued once
     ↓
Reusable during session
     ↓
Invalidated with its lifecycle

Per-request / one-time token:

Issued
     ↓
Used once
     ↓
Invalidated

You've completed Cross Site Request Forgery

Great work — explore other topics to keep learning.