Summary
Cross-Site Request Forgery (CSRF) is a web vulnerability that tricks a logged-in user’s browser into sending unauthorized requests to a trusted application. Common CSRF variants include stored, reflected, login, and multi-step attacks. Prevention requires layered defenses such as anti-CSRF tokens, SameSite cookies, Origin/Referer validation, and custom headers.
What Is Cross-Site Request Forgery (CSRF)?
Cross-Site Request Forgery (CSRF or XSRF) is a web security vulnerability where an attacker tricks a victim’s browser into performing unwanted actions on a trusted site where the user is already authenticated. It bypasses the same-origin policy to change state without consent, for example by changing passwords or transferring funds. In a CSRF attack, the victim is typically unaware that unauthorized actions have taken place, as the malicious requests are indistinguishable from legitimate user actions by the server.
The core issue with CSRF is that web applications often rely on authentication credentials that browsers automatically send with every request, such as cookies. If a user is logged in to a site, an attacker can exploit this trust by crafting a request that the browser sends with those credentials. As a result, sensitive operations—like changing account details, making purchases, or transferring funds—can be performed without the user’s knowledge or consent.
This is part of a series of articles about application security
How Do CSRF Attacks Work?
CSRF is possible because browsers automatically include certain authentication credentials, especially cookies, when sending requests to a website. After a user logs in to a trusted site, the site usually stores a session cookie in the browser.
Depending on the cookie’s attributes and the type of request, the browser may automatically include that session cookie when a request is sent to the trusted site – even when another site initiated the request. CSRF becomes possible when those credentials are included and the application has no additional mechanism for verifying that the user intended the action.
This creates a security risk when the trusted website uses the presence of the cookie as proof that the user intentionally made the request. The browser can prove that the request came from an authenticated user’s session, but it cannot prove that the user actually meant to perform the action. An attacker takes advantage of this gap by causing the victim’s browser to send a request to the trusted site while the victim is still logged in.
A typical CSRF attack proceeds as follows:
- The victim logs in to a trusted website, such as a banking, email, shopping, or admin portal.
- The trusted website stores an authentication cookie in the victim’s browser.
- The victim visits a malicious website, opens a malicious email, or clicks a crafted link controlled by the attacker.
- The attacker’s page causes the victim’s browser to send a request to the trusted website, such as submitting a form or loading a URL that performs a state-changing action.
- Because the victim is already authenticated, the browser automatically includes the victim’s session cookie with the request.
- If the trusted website does not use proper CSRF protections, it treats the request as legitimate and performs the action.
Conditions for CSRF to succeed:
- The victim must be authenticated to the target website, and their browser must still hold valid credentials for that site.
- The target website must perform a sensitive action based on a predictable request, such as a known URL, form fields, or parameters.
- The website must rely only on automatically sent credentials, such as cookies, without requiring an additional anti-CSRF token or another proof of user intent.
- The attacker must be able to manipulate the browser to send the request, for example through a malicious webpage, hidden form, image tag, script, or link.
Who Needs to Protect Against CSRF?
CSRF protection is particularly important for web applications that use browser-managed credentials, such as session cookies, to authenticate requests that can change application state.
This includes consumer and enterprise applications with account settings, financial or commerce transactions, administrative interfaces, content-management functions, cloud consoles, and other workflows where an authenticated user can create, update, delete, approve, or transfer information.
Developers should pay particular attention to applications where:
- users remain authenticated for extended periods;
- sensitive actions are performed through predictable URLs or parameters;
- session cookies are automatically included with requests;
- state-changing endpoints do not require a CSRF token or independent origin check;
- or privileged administrators use browser-based management interfaces.
API designs that authenticate exclusively through authorization headers rather than automatically attached cookies generally have a different CSRF risk model, but APIs using cookie-based authentication can still require CSRF defenses.
Types of CSRF Attacks with Examples
Examples and mitigations in this section are adapted from the OWASP CSRF Cheat Sheet.
1. Stored CSRF
Stored CSRF occurs when the malicious CSRF payload is saved inside the target application and later executed when another user views that stored content. This makes the attack more persistent than a normal one-time CSRF link because the victim does not need to visit an external malicious website. Instead, the attack is delivered from inside the trusted application itself.
A stored CSRF attack usually requires the following conditions to succeed:
- The application allows user-controlled content to be stored and later displayed to other users.
- The stored content can trigger a request, such as through HTML, an image tag, an iframe, or a form.
- The victim is authenticated when they view the stored content.
- The target action is predictable and does not require a valid anti-CSRF token.
- The server relies only on automatically sent credentials, such as cookies, to authorize the action.
Consider a CSRF attack in which an attacker exploits a vulnerable online forum. The attacker posts a comment, profile field, message, or forum post that contains hidden HTML designed to trigger a state-changing request when an authenticated user views the page. If an administrator views the attacker’s stored content while logged in, their browser may automatically send the forged request with their valid session cookie.
Stored CSRF can be stored in the vulnerable site itself, for example by saving an IMG or IFRAME tag in a field that accepts HTML.
<img src="http://bank.com/transfer.do?acct=MARIA&amount=100000" width="0" height="0" border="0">
This example shows how an image tag can trigger a state-changing GET request without visible user interaction.
Mitigations include:
- Use anti-CSRF tokens on all state-changing requests and validate them on the server.
- Bind CSRF tokens to the user’s session so one user’s token cannot be reused by another.
- Sanitize and encode user-generated content to prevent stored HTML or JavaScript execution.
- Use the SameSite cookie attribute as a defense-in-depth measure.
- Require re-authentication or step-up verification for highly sensitive actions.
- Do not allow state-changing actions through simple GET requests.
2. Classic Authenticated-Action CSRF (Reflected CSRF)
Classic authenticated-action CSRF is the most familiar form of the attack. An attacker causes an authenticated user’s browser to send a state-changing request to a trusted application from an external page, link, email, advertisement, or other attacker-controlled location.
Unlike stored CSRF, the request trigger is not saved inside the target application. The attacker instead creates a request that matches a legitimate application action – for example, changing an email address, modifying account settings, or initiating a transaction – and tricks the victim’s browser into sending it while the victim is authenticated.
A Classic CSRF attack typically requires the following conditions to succeed:
- The victim is logged in to the target site.
- The browser automatically sends authentication credentials, such as session cookies.
- The attacker knows or can guess the target URL and required parameters.
- The sensitive action can be triggered cross-site, such as by a form, image, iframe, or link.
- The request does not require a secret, unpredictable value such as a valid CSRF token.
- The application does not properly validate the request’s origin.
Here is a simple reflected GET-based CSRF example in which an attacker disguises a malicious transfer URL as a normal link:
<a href="http://bank.com/transfer.do?acct=MARIA&amount=100000">View my Pictures!</a>
And another example of POST-based CSRF using a hidden form:
<form action="http://bank.com/transfer.do" method="POST">
<input type="hidden" name="acct" value="MARIA"/>
<input type="hidden" name="amount" value="100000"/>
<input type="submit" value="View my pictures"/>
</form>
The form can be auto-submitted with JavaScript:
<body onload="document.forms[0].submit()">
Mitigations include:
- Require unpredictable CSRF tokens for all state-changing actions.
- Validate the token on the server before performing the action.
- Use SameSite=Lax or SameSite=Strict cookies where appropriate.
- Validate the Origin and/or Referer headers as defense-in-depth.
- Avoid using GET requests for actions that modify server-side state.
- Use custom headers for AJAX/API requests, because simple cross-origin HTML forms cannot set arbitrary custom headers without CORS permission.
3. Login CSRF
Login CSRF is a variation of CSRF where the attacker forces the victim’s browser to log in to the target site using the attacker’s account. This does not necessarily take over the victim’s existing account, but it can still be dangerous because the victim may unknowingly perform actions inside an attacker-controlled account.
Unlike classical CSRF, the attacker is not necessarily trying to perform an action inside the victim’s existing account; the attacker is manipulating which authenticated account the victim’s browser uses.
For example, an attacker may create an account on a shopping website and then trick the victim’s browser into logging in as that attacker. The victim might later add payment information, shipping addresses, private documents, search history, or other sensitive data to the attacker’s account, believing they are using their own account.
Login CSRF can be especially harmful on sites where users store payment methods, addresses, personal data, cloud files, browser sync information, or other long-term account data.
Mitigations include:
Protect login forms with CSRF tokens, not only authenticated state-changing forms.
Regenerate the session after login to prevent session fixation.
Clearly show the logged-in user identity after authentication.
Require confirmation before adding sensitive data such as payment methods or recovery emails.
Use SameSite cookies to reduce cross-site credential submission.
Monitor suspicious login flows and account-switching behavior.
Although many developers focus CSRF protection only on authenticated actions, login endpoints can also need CSRF protection because a forged login can alter the user’s security context.
4. Client-Side and Advanced CSRF
Client-side CSRF occurs when attacker-controlled input causes trusted JavaScript in the application to generate an unintended authenticated request. In this case, the attacker is not relying only on a hidden cross-site form or image request. Instead, vulnerable client-side logic acts as a confused deputy, transforming attacker-controlled input into a trusted request.
This pattern can be particularly difficult to prevent because the application’s own JavaScript may automatically attach credentials, CSRF tokens, or custom headers. As a result, server-side defenses that would block a conventional cross-site form may not stop a request generated by trusted client-side code.
Advanced CSRF attacks can also involve multiple requests, inconsistent protection across related endpoints, or chaining CSRF with another weakness. The underlying security requirement remains the same: attacker-controlled input must not be able to cause privileged state-changing actions without appropriate validation and authorization.
Here is a client-side CSRF example, where attacker-controlled URL fragments are used by JavaScript to generate an authenticated request:
<script type="text/javascript">
const csrf_token = document.querySelector("meta[name='csrf-token']").getAttribute("content");
const ajaxLoad = () => {
const hashFragment = window.location.hash.slice(1);
if (hashFragment.length > 0 && hashFragment.includes(';')) {
const params = hashFragment.match(/^(get|post);(.*)$/);
if (params && params.length) {
const requestMethod = params[1];
const requestEndpoint = params[2];
fetch(requestEndpoint, {
method: requestMethod,
headers: {
'X-CSRF-Token': csrf_token,
},
})
}
}
};
window.addEventListener('DOMContentLoaded', ajaxLoad);
</script>
This is vulnerable because the JavaScript uses attacker-controlled URL-fragment input to choose the request method and endpoint, while still attaching CSRF protections such as a token header.
Mitigations include:
- Apply CSRF protection consistently to every state-changing endpoint.
- Use server-generated, unpredictable CSRF tokens.
- Bind tokens to the user’s session.
- Reject requests with missing or invalid CSRF tokens.
- Do not allow method override or alternate HTTP methods to bypass CSRF checks.
- Validate Origin and Referer headers as additional protection.
- Use SameSite cookies, preferably Lax or Strict depending on the application’s needs.
- Use Secure and HttpOnly cookie attributes for session cookies.
- Require re-authentication, MFA, or explicit confirmation for high-risk actions.
- Remember that XSS can bypass CSRF defenses, so XSS prevention must also be part of the overall mitigation strategy.
CSRF vs. XSS vs. Clickjacking vs. Session Hijacking
The following table shows a quick comparison between the four attack types. Below we cover the differences in more detail.
| Attack | Core Mechanism | Typical Impact | Main Defenses |
| CSRF | Causes the victim’s browser to send an unintended authenticated request | Unauthorized state-changing actions | CSRF tokens, origin validation, Fetch Metadata, SameSite |
| XSS | Executes attacker-controlled script in the trusted site’s origin | Data theft, account compromise, malicious actions | Context-aware output encoding, safe frameworks, CSP, secure coding |
| Clickjacking | Tricks the user into interacting with hidden or disguised UI | Unintended clicks or approvals | CSP frame-ancestors, framing restrictions |
| Session Hijacking | Steals or obtains control of the victim’s session identifier | Direct account impersonation | TLS, secure cookies, session controls, MFA |
These attack types can also be chained. XSS is particularly important because attacker-controlled JavaScript executing within the trusted application’s origin can often defeat CSRF defenses, including reading or using valid CSRF tokens. Clickjacking can also be combined with sensitive workflows by deceiving users into interacting with legitimate application controls.
CSRF vs. XSS
CSRF tricks the victim’s browser into sending an unwanted request to a trusted website where the victim is already authenticated. The attacker usually does not need to read the response or steal data directly. Instead, the goal is to make the application perform an action using the victim’s existing session, such as changing an email address, submitting a form, or transferring funds.
XSS occurs when an attacker injects malicious JavaScript into a trusted website so that the script runs in another user’s browser. With XSS, the attacker’s code executes inside the security context of the vulnerable site. This can allow the attacker to read page content, steal sensitive data, perform actions as the user, modify the page, capture keystrokes, or bypass other security controls.
The main difference is that CSRF abuses the browser’s automatic submission of credentials, while XSS abuses the website’s failure to safely handle untrusted input. A key security point is that XSS can often defeat CSRF protections. If an attacker can run JavaScript inside the trusted site, they may be able to read CSRF tokens from the page or submit valid requests directly.
CSRF vs. Clickjacking
CSRF does not usually require the victim to interact with the real target website. The attacker can cause the victim’s browser to send a hidden request automatically, such as through a hidden form, image tag, iframe, or script. The attack relies on the browser automatically including authentication credentials, such as session cookies.
Clickjacking, also known as a UI redress attack, tricks the user into clicking on something different from what they believe they are clicking. The attacker may load the legitimate website inside a hidden or transparent iframe and place misleading buttons, text, or graphics over it. When the victim clicks, they are actually clicking a real button or control on the trusted website.
CSRF and clickjacking can also be combined. For example, clickjacking may be used to trick the user into pressing a button that submits a legitimate form, while CSRF may be used to forge the underlying request if the application does not require a valid token.
CSRF vs. Session Hijacking
In CSRF, the attacker does not need to steal the victim’s session cookie or know the victim’s password. The attacker relies on the victim’s own browser to send authenticated requests. The victim remains logged in, and the forged request is sent from the victim’s browser with the victim’s credentials automatically attached.
In session hijacking, the attacker obtains or takes control of the victim’s session identifier, such as a session cookie or token. Once the attacker has the session token, they can impersonate the victim directly, often from the attacker’s own browser or tools, without needing the victim to visit a malicious page again.
The main difference is that CSRF abuses an existing authenticated browser session without stealing it, while session hijacking steals or takes over the session itself. CSRF is about unauthorized actions through the victim’s browser; session hijacking is about unauthorized access as the victim.
Prevent attacks like CSRF throughout the SDLC Title: Checkmarx SAST
Title: Strengthen Secure Development with Checkmarx SAST
Analyze application code for security weaknesses and give developers actionable feedback earlier in IDE and CI/CD workflows.
7 Ways to Prevent CSRF Attacks
Here are widely accepted best practices to prevent CSRF attacks on a website.
1. Use Anti-CSRF Tokens
Anti-CSRF tokens are unpredictable values that the application associates with a user’s authenticated session or request. The application includes the token in legitimate forms or requests and validates it on the server before executing a state-changing action.
For stateful applications, the synchronizer token pattern is a common implementation. The server generates a token associated with the user’s session and requires it on protected requests. Because an attacker on another site cannot normally obtain the user’s valid token, a forged request is rejected.
Stateless applications may use an appropriately implemented signed double-submit cookie pattern. Tokens should be generated securely, validated server-side, and never exposed unnecessarily in URLs, logs, or other locations where they may leak.
Anti-CSRF tokens should be applied consistently to sensitive state-changing operations. They are powerful protection against classical CSRF, but applications must also prevent XSS because script executing within the trusted origin may be able to access or use valid tokens.
2. Set SameSite Cookies Appropriately
The SameSite cookie attribute limits when browsers send cookies with cross-site requests and can significantly reduce CSRF exposure.
SameSite=Strict provides the strongest restriction by withholding the cookie from cross-site requests. SameSite=Lax provides a balance between security and usability but can still allow the cookie on some top-level cross-site navigations using safe HTTP methods such as GET.
Use Strict where application behavior permits and Lax where legitimate cross-site navigation requires session continuity. Cookies that must use SameSite=None require particularly careful CSRF protection because they are intentionally available in cross-site contexts.
SameSite should usually be treated as defense in depth, not as a substitute for request-specific CSRF validation.
3. Validate Request Origin
Applications can reject suspicious cross-site requests by checking where the request originated.
Modern browsers provide Fetch Metadata headers such as Sec-Fetch-Site, which indicate whether a request is same-origin, same-site, or cross-site. Sensitive endpoints can use this information to reject clearly cross-site requests when those requests are not expected.
Applications can also validate the Origin header and use Referer as a fallback when appropriate. Origin validation should compare requests against an explicit allowlist of trusted origins rather than relying on loose substring matching.
These checks complement anti-CSRF tokens and are especially useful as an additional control against unexpected cross-site requests.
4. Use Custom Headers and Non-Simple Requests for APIs
JavaScript applications and APIs can require requests to include a custom header or use request formats that browsers cannot submit through a simple cross-site HTML form.
For example, an application may require a custom CSRF header that legitimate client-side code adds to state-changing API requests. A malicious external page cannot generally add arbitrary headers to another origin without triggering browser CORS controls.
This approach depends on strict CORS configuration. Applications should explicitly allow trusted origins and avoid configurations that permit untrusted sites to make credentialed cross-origin requests.
Custom-header defenses are particularly relevant for single-page applications and APIs but should be combined with appropriate session, origin, and authorization controls.
5. Protect Every State-Changing Endpoint
CSRF defenses must cover every request capable of modifying server-side state. Protecting only high-profile actions leaves alternative or legacy endpoints available for exploitation.
Applications should avoid using GET for state-changing operations. Actions such as password changes, account updates, purchases, transfers, user creation, permission changes, and administrative configuration should use appropriate state-changing methods and require consistent CSRF validation.
Protection must also apply to alternate endpoints, method overrides, mobile or legacy interfaces, and secondary workflows that perform the same sensitive operation.
For particularly high-risk actions, applications may add stronger proof of user intent through re-authentication, MFA, or explicit confirmation.
6. Centralize CSRF Defenses in Framework Middleware
CSRF controls are easier to apply consistently when they are implemented through standardized framework mechanisms rather than custom code scattered across individual endpoints.
Where supported, use established framework middleware, filters, interceptors, decorators, or security libraries that automatically generate and validate CSRF protections. Centralized controls reduce the likelihood that a developer will accidentally leave one endpoint unprotected.
Consistent implementation also improves code review and automated security analysis. Developers and security tools can more easily identify exceptions, missing protections, or unsafe overrides when the application’s expected CSRF-protection pattern is clear in the codebase.
Framework-level controls should still be tested and reviewed. Teams should verify that they cover every relevant endpoint and that custom application behavior has not unintentionally bypassed the protection.
Finding CSRF Risk Earlier with Checkmarx SAST
CSRF weaknesses originate in application logic and request-handling patterns, making source-code analysis a useful part of a broader prevention strategy. The application itself still needs appropriate CSRF controls—such as secure framework protections, request validation, and correctly configured session handling—but SAST can help teams identify insecure implementation patterns earlier in development.
Checkmarx SAST analyzes application code to identify security weaknesses before software reaches production. Integrated into developer and CI/CD workflows through Checkmarx One, it helps developers and AppSec teams find relevant code-level issues while changes are still easier to review and remediate.
Key capabilities include:
- Detect code-level security weaknesses: Analyze application code and data flows to identify potentially exploitable implementation problems across supported languages and frameworks.
- Bring security feedback into developer workflows: Run security analysis in IDE, pull-request, and CI/CD workflows so developers can address issues before merge or release.
- Support consistent secure coding practices: Apply centralized security policies and scanning practices across applications and development teams.
- Provide contextual remediation guidance: Give developers explanations and guidance that help them understand security findings and determine the appropriate fix.
- Connect code findings to broader AppSec context: Use Checkmarx One to manage SAST findings alongside other application-security signals, policies, and risk context.
CSRF is best prevented by implementing the correct controls in application code and frameworks. SAST supports that goal by helping teams identify security weaknesses and inconsistent implementation patterns earlier in the SDLC.
Conclusion
CSRF exploits the difference between an authenticated request and an intentional authenticated action. When browsers automatically supply session credentials and applications do not independently verify request intent, attackers may be able to make users perform actions they never intended.
Modern browser protections have reduced some classical CSRF attack paths, but CSRF remains relevant wherever applications rely on cookie-based authentication and sensitive state-changing requests. Effective defense requires layered controls: anti-CSRF tokens where appropriate, correctly configured SameSite cookies, request-origin validation, secure API request patterns, consistent protection of state-changing endpoints, and centralized framework defenses.
Security testing should complement these controls rather than replace them. By making CSRF protections consistent, visible in code, and reviewable throughout development, teams can reduce the chance that a missing or misconfigured defense becomes exploitable in production.