ofensiva
CSRF
XSRF
cross-site request forgery

What is CSRF: cross-site request forgery, examples and defense

What CSRF (cross-site request forgery) is, how it works, exploit examples, defenses (CSRF tokens, SameSite cookies) and the difference with XSS.

SecraJune 8, 202612 min read

CSRF (cross-site request forgery, also written as XSRF) is a web vulnerability in which an attacker forces the browser of an already authenticated victim to execute unintended actions on an application where the victim holds an active session. The attack does not steal the cookie or break encryption: it exploits the fact that the browser automatically attaches session credentials to any request directed at the target domain, even when that request originates from a page controlled by the attacker. The application receives the request as if it were legitimate and executes it because it trusts the user's browser.

The essentials. CSRF exploits the server's trust in the authenticated browser, not in the user. Modern defenses combine anti CSRF tokens (synchronizer pattern), SameSite=Lax or Strict cookies, validation of Origin and Referer headers, and re authentication on critical operations. Frameworks such as Django, Rails, Spring Security, ASP.NET and Laravel ship with protection enabled, but only if the configuration is not switched off.

What CSRF is: step by step mechanism

The flow of a CSRF attack relies on three simultaneous elements: an authenticated victim, an application that trusts browser cookies to authorise actions, and a page or resource controlled by the attacker that the victim visits or loads without noticing.

The first step is the active session. The victim signs in to a legitimate application (a banking dashboard, a corporate CMS, an internal service). The server issues a session cookie that the browser stores for that domain. That cookie travels in every subsequent request to the same origin.

The second step is the attacker page. The victim visits another site (a blog, a forum, an HTML email, a social media link) where the attacker has placed crafted code: a form auto submitted via JavaScript, an <img> tag firing a GET request, or a fetch() with credentials: 'include'. The browser interprets that code like any other resource.

The third step is silent execution. When the browser performs the forged request against the victim domain, it automatically attaches the stored session cookie. The server receives valid credentials, identifies the user and executes the action (transfer, password change, administrator promotion) without the victim having clicked anything other than an external page. Confirmation does not even need to flow back to the attacker: it is enough for the action to complete on the server.

The critical point is that the application does not distinguish between a request originating in its own interface and one originating in a third party, unless it implements specific checks. That indistinction is the foundation of the attack.

Technical example of a CSRF exploit

Below are two classic patterns. They are shown for didactic and defensive auditing purposes.

GET request triggered by an image embedded in a malicious HTML email or web page:

<img src="https://victim-app.tld/transfer?destination=attacker&amount=5000" width="0" height="0" />

If the application processes transfers via GET (a recurring bad practice in legacy code) and the victim opens the email or page while signed in, the browser performs the request and the session cookie is included.

POST request via auto submitted form:

<form id="f" action="https://victim-app.tld/account/change-email" method="POST">
  <input type="hidden" name="email" value="attacker@malicious.tld" />
</form>
<script>document.getElementById('f').submit();</script>

The form is submitted without user interaction. The session cookie travels with the request. If there is no anti CSRF token and no Origin validation, the application changes the email address associated with the account, which opens the door to a subsequent password reset.

These patterns are trivially reproducible in a controlled lab (for example, DVWA, PortSwigger Web Security Academy or in house environments) and are part of any responsible web audit.

CSRF vs XSS vs SSRF: key differences

VectorPayload originWhat is exploitedWho executes
CSRFExternal site controlled by the attackerServer trust in automatic cookiesVictim's browser
XSSInjection into the vulnerable application itselfBrowser trust in the originVictim's browser (with the domain's permissions)
SSRFControllable parameter sent to the backendServer trust in its own outbound requestsApplication server

CSRF and XSS often coexist: a successful XSS nullifies any CSRF protection because the attacker can read the token from inside the domain. That is why XSS is usually considered more severe and CSRF complements the catalogue of defenses in depth.

Types of CSRF attack

GET based CSRF. Works when the application exposes state changing actions through GET requests. It is the easiest case to exploit because an <img>, <link> or redirect tag is enough.

POST based CSRF. Requires an auto submitted form or a fetch() with credentials. It is the classic scenario against web panels.

JSON based CSRF. Historically considered safe because requests with Content-Type: application/json trigger a CORS preflight. However, prefetch tricks, forms with enctype="text/plain" and poorly configured APIs that accept application/x-www-form-urlencoded as an alternative have allowed bypasses in real world applications.

Login CSRF. The attacker does not force an action while authenticated as the victim, but rather forces the victim to log in with the attacker's credentials. The victim believes she is using her own account and delivers data (searches, messages, payment methods) that the attacker retrieves later by returning to the session.

State changing operations. Any endpoint that alters persistent data (email change, password change, address, permissions, subscriptions, payments) is a candidate for CSRF auditing. Read only idempotent endpoints do not require protection, but they require review to confirm that they really do not modify state.

Modern defenses

CSRF tokens (synchronizer pattern)

The server generates a random token per session (or per request), embeds it in each form or exposes it through an endpoint for JavaScript clients, and validates it on every state changing action. The token must not travel in the session cookie and must be unpredictable. This is the reference defense and the one implemented by mature frameworks.

The server sets a cookie with a random value and requires every state changing request to include that same value in a custom header or form field. The server compares both. It is useful in architectures without a classic session, but requires care with cookie scope and value integrity.

SameSite cookies (Lax, Strict, None)

SameSite=Strict prevents the cookie from being sent in any cross site request, including top level links. SameSite=Lax (default value in modern browsers) blocks cookies in POST and cross site subresources, but allows them in top level GET navigation. SameSite=None is only used with Secure and removes protection, so it requires complementary anti CSRF tokens.

Origin and Referer header validation

The browser attaches Origin in POST and CORS requests, and Referer in most requests. The server can reject requests whose origin does not match the expected allow list. It is a simple and inexpensive defensive layer, complementary to tokens.

Custom request headers + CORS preflight

If the endpoint requires a custom header (for example, X-Requested-With: XMLHttpRequest or X-CSRF-Token: ...), the browser will trigger an OPTIONS preflight for cross origin requests, which lets the server reject them. This technique works well on APIs consumed by first party SPAs.

Re authentication on critical actions

Password change, account deletion, fund transfers and permission modifications should require password or second factor, not only session cookie. It is the strongest defense against CSRF and other vectors where the session may be compromised.

Framework defaults

Django (CsrfViewMiddleware), Rails (protect_from_forgery), Spring Security (CsrfFilter), ASP.NET Core (AntiforgeryToken) and Laravel (VerifyCsrfToken) ship with active protection by default. The root cause of most modern CSRF findings is not the absence of the defense, but its deliberate deactivation for quick integrations, API endpoints miscategorised as non state changing, or generic exclusions in configuration.

Real cases and public CVEs

CSRF appears recurrently in the CVE catalogue, especially in WordPress plugins, legacy admin panels, IoT devices with web interfaces and unpatched enterprise software. Searches in the NVD for CSRF or cross-site request forgery return entries covering configuration changes in home routers, account modifications in CMS, execution of administrative actions in DevOps tools and privilege escalation in internal applications. The common pattern is the same: state changing endpoint, cookie based session, missing token or origin validation.

This is not about glamorising exploits, but about underlining that the vulnerability remains active in real code, particularly in legacy software, third party plugins and endpoints added after the fact without reviewing the main framework's anti CSRF configuration.

CSRF in REST and GraphQL APIs

A SPA that authenticates via a JWT token sent in the Authorization: Bearer ... header is naturally immune to classic CSRF: the browser does not automatically attach that header on cross origin requests, and the attacker cannot read the token from another domain thanks to the same origin policy.

The scenario changes when authentication is cookie based, even if the API is REST or GraphQL. Cookies with SameSite=None (required in multi domain architectures) reintroduce the risk and require explicit anti CSRF protection: tokens in custom header, Origin validation, or double verification with cookie and header.

In GraphQL, the risk concentrates on mutations. A mutation exposed via POST with Content-Type: application/json is covered by the preflight, but some implementations accept application/x-www-form-urlencoded or GET for queries, and that flexibility can be exploited. The recommendation is to explicitly restrict accepted content types and require a custom header on every mutation.

How to test CSRF in an audit

Web scanning tools that automate testing (Burp Suite, ZAP, Acunetix, Nessus) detect missing tokens and insecure SameSite configurations, but manual confirmation remains essential. The typical flow in an audit:

  1. Identify state changing endpoints through authenticated crawling.
  2. Capture the legitimate request with Burp and replay it without the token and with a modified Origin.
  3. Build a test page with an auto submitted form or a cross origin fetch().
  4. Verify whether the action completes with the victim's active session.
  5. Try variants: equivalent GET, alternative content types, login CSRF, GraphQL mutations.

Patterns that automators miss: predictable tokens, tokens reused across sessions, permissive Origin validation with wildcards, ad hoc middleware exclusions, and API endpoints added outside the main flow without protection. Those findings only appear with manual review and knowledge of the framework.

Regression tests should cover every state changing endpoint with a negative case (request without token, request with external origin) that runs in CI to prevent regressions when CSRF middleware is mistakenly disabled.

Fit with the OWASP Top 10

CSRF appeared as a standalone category in the OWASP Top 10 until 2017 (A8: Cross-Site Request Forgery). In the 2021 edition it disappeared as a category of its own because the widespread adoption of framework defenses reduced its relative prevalence. Today the risk is categorised within Broken Access Control (A01:2021) when the endpoint does not adequately verify the origin of the request.

Removal from the Top 10 does not imply that the risk has vanished. It means the ratio of vulnerable applications is lower than for other categories. In legacy code, third party plugins and poorly configured APIs, CSRF remains a frequent finding in professional audits.

Frequently asked questions

Is CSRF still relevant in 2026?

Yes. Although modern frameworks protect by default, the problem persists in legacy code, plugins, quick integrations with CSRF disabled, and cookie based APIs with SameSite=None. Any serious web audit keeps CSRF on its checklist.

Is SameSite=Lax enough?

SameSite=Lax covers most POST vectors and eliminates trivial attacks based on cross site forms. It does not cover top level GET or complex scenarios with redirects. The professional recommendation is to combine SameSite=Lax or Strict with anti CSRF tokens for defense in depth.

Does the CSRF token break APIs?

No, if it is designed correctly. APIs authenticated by Bearer token in header do not need a CSRF token. APIs authenticated by cookie should expose an endpoint to obtain the token or use the double submit cookie pattern. The problem appears when both models are mixed without coherence.

Is there CSRF in GraphQL?

Yes, in mutations exposed with cookie authentication and relaxed content type acceptance. The defense is the same as in REST: tokens, Origin validation, strict content type and mandatory preflight through a custom header.

What is login CSRF?

It is the variant in which the attacker forces the victim to log in with the attacker's credentials. The victim then generates activity (searches, messages, payment methods) that the attacker retrieves later. It is mitigated with anti CSRF tokens also on the login form and with post login browser verification.

When do I NOT need to protect an endpoint?

Strictly idempotent and read only endpoints (pure GET with no side effects) do not require a CSRF token. But that classification must be verified: many apparently read only endpoints update logs, counters or session state and should be protected.

Auditing CSRF and web vulnerabilities with Secra

Secra performs web application audits aligned with the OWASP Top 10 and the OWASP Web Security Testing Guide. We cover identification of state changing endpoints, verification of anti CSRF tokens, analysis of SameSite configuration, testing on REST and GraphQL APIs, and review of the framework configuration (Django, Rails, Spring, ASP.NET, Laravel) to confirm that default defenses have not been disabled in ad hoc integrations.

We deliver prioritised findings, reproducible test cases and hardening recommendations specific to your architecture. We also design regression test suites that integrate into CI to prevent reintroducing vulnerabilities when the team modifies middleware or adds new endpoints.

If you need a professional review of CSRF, XSS, SSRF and the rest of the OWASP catalogue, write to us through /en/contact/ and we will plan an audit adapted to the scope of your platform.

About the author

Secra Solutions team

Ethical hackers with OSCP, OSEP, OSWE, CRTO, CRTL and CARTE certifications, 7+ years of experience in offensive cybersecurity, and authors of CVE-2025-40652 and CVE-2023-3512.

Share article