What is Cross-Site Request Forgery?
Cross-Site Request Forgery (CSRF) is an attack that forces an authenticated user to unknowingly execute unwanted actions on a web application. The attacker crafts a malicious page or email that causes the victim’s browser to send a forged request — carrying the victim’s session cookies — to a trusted site.
Unlike Cross-Site Scripting (XSS), which exploits the user’s trust in a site, CSRF exploits the site’s trust in the user’s browser. If the victim is logged in to a banking application and visits an attacker-controlled page, that page can silently trigger a funds transfer on their behalf.
CSRF affects any application that relies solely on cookies or HTTP authentication to authorize requests, and where state-changing operations can be triggered via GET or unauthenticated POST.
How exploitation works
The attacker hosts a page containing a hidden form that targets the victim’s authenticated session:
<!-- Attacker's page — victim visits this link -->
<form action="https://bank.example.com/transfer" method="POST" id="csrf">
<input type="hidden" name="to" value="attacker_account" />
<input type="hidden" name="amount" value="10000" />
</form>
<script>document.getElementById('csrf').submit();</script>
When the victim’s browser submits this form, it automatically includes the session cookie for bank.example.com, making the request appear legitimate to the server.
Vulnerable code examples
ASP.NET Core — missing CSRF validation
// VULNERABLE: No [ValidateAntiForgeryToken] attribute
[HttpPost]
public IActionResult ChangeEmail(string newEmail)
{
var userId = User.GetUserId();
_userService.UpdateEmail(userId, newEmail);
return Ok();
}
Java Spring — CSRF disabled
// VULNERABLE: CSRF protection explicitly disabled
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable(); // Never disable in production
}
}
Secure code examples
ASP.NET Core — CSRF token validation
// SECURE: Enforce anti-forgery token on all state-changing endpoints
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult ChangeEmail(string newEmail)
{
var userId = User.GetUserId();
_userService.UpdateEmail(userId, newEmail);
return Ok();
}
Python / Django — built-in CSRF middleware
# SECURE: Django's CsrfViewMiddleware is enabled by default.
# Include {% csrf_token %} in every form.
# For AJAX, read the csrftoken cookie and send as X-CSRFToken header.
# settings.py
MIDDLEWARE = [
'django.middleware.csrf.CsrfViewMiddleware', # Must be present
...
]
What Offensive360 detects
- Missing CSRF token validation — State-changing endpoints (POST, PUT, PATCH, DELETE) lacking framework-level CSRF protection
- Explicitly disabled CSRF middleware — Calls to
csrf().disable(),@csrf_exempt, or equivalent that remove built-in protections - GET-based state changes — Endpoints that perform writes triggered by HTTP GET requests
- Missing SameSite cookie attribute — Session cookies issued without
SameSite=LaxorStrict - Insecure API token usage — Endpoints that accept authentication only via cookies without a secondary CSRF check
Remediation guidance
-
Use synchronizer token pattern — Generate a unique, unpredictable token per session and validate it on every state-changing request.
-
Set SameSite=Lax or Strict on session cookies — Modern browsers block cross-origin cookie sending for requests that match SameSite restrictions. This is a strong, low-friction defense.
-
Validate the Origin/Referer header — Reject requests where the
OriginorRefererdoes not match your application’s domain. -
Use framework defaults — ASP.NET Core, Django, Rails, and Spring all include CSRF protection. Enable and configure it rather than building custom solutions.
-
Prefer custom request headers for APIs — AJAX requests can include a custom header (e.g.,
X-Requested-With) that browsers cannot send cross-origin without CORS approval.