Cross-Site Request Forgery: Understanding the Mechanics
Cross-Site Request Forgery (CSRF), often called “Session Riding,” is a vulnerability where an attacker tricks a legitimate user into performing an unwanted action on a web application where they are currently authenticated.
Unlike XSS, which steals the user’s data (like cookies), CSRF exploits the fact that the browser automatically sends those cookies to the server, allowing the attacker to “ride” the user’s active session.
🔸 1. What is CSRF?
CSRF allows an attacker to induce a victim user to perform actions that they do not intend to perform.
The Attack Scenario:
- A user is logged into
vulnerable.com. - The user visits
malicious.com(controlled by the attacker). malicious.comsecretly sends a request tovulnerable.com.- The browser automatically attaches the user’s session cookies.
vulnerable.comprocesses the request, thinking the user initiated it.

The Core Concept: The “Confused Deputy”
The web server acts as a “Deputy.” It checks for your badge (Session Cookie) to allow entry.
- *The Flaw:** The browser automatically attaches your badge to every request sent to the bank, even if that request originated from a malicious site.
- The Confusion:** The server sees the badge and processes the request, assuming *you made it.
⚙️ 2. The Mechanics: How the Browser Betrays You
To understand CSRF, you must understand how browsers handle credentials.
The Automatic Cookie Transmission
When you log in to vulnerable-website.com, the server gives you a session cookie (e.g., session=abc123xyz).
- The Rule: Whenever the browser sends a request to
vulnerable-website.com, it automatically includes that cookie. - The Exploit: An attacker creates a malicious site (
evil.com) containing a hidden form that submits tovulnerable-website.com. When you visitevil.com, your browser submits the form and dutifully attaches your valid session cookie.
🧨 3. Anatomy of an Attack
Attackers use different HTML elements to trigger the forgery depending on the HTTP method required by the action.
1️⃣ The GET Request (The Simple Image)
If the application uses GET requests for sensitive actions (bad practice), the attack is trivial. The attacker embeds the URL in an image tag.
Payload:
<img src="[https://vulnerable-website.com/email/change?email=pwned@evil-user.net](https://vulnerable-website.com/email/change?email=pwned@evil-user.net)">
Execution: The moment the victim loads the page, the browser tries to fetch the “image.” This sends a GET request to the vulnerable site with the victim’s cookies.
2️⃣ The POST Request (The Hidden Form)
If the application correctly uses POST, the attacker uses a hidden HTML form and JavaScript to auto-submit it.
Payload:
<html>
<body>
<form action="[https://vulnerable-website.com/email/change](https://vulnerable-website.com/email/change)" method="POST">
<input type="hidden" name="email" value="pwned@evil-user.net" />
</form>
<script> document.forms[0].submit(); </script>
</body>
</html>
Execution: The user visits the attacker’s site. The script executes immediately (document.forms[0].submit()), sending the POST request to the target.
3️⃣ Stealth iframe Attack
To prevent the user from noticing the attack (e.g., the page redirecting), attackers use an invisible iframe as the target for the form submission.
Payload:
<iframe name="stealth_frame" style="display:none;"></iframe>
<form id="csrf_form" action="[http://bank.com/transfer](http://bank.com/transfer)" method="POST" target="stealth_frame">
<input type="hidden" name="amount" value="5000">
</form>
<script> document.getElementById('csrf_form').submit(); </script>
Execution: The form submits inside the invisible iframe. The user remains on the attacker’s page, unaware that the transfer has occurred in the background.
🛡️ 4. Defenses: The Shield
Web applications rely on three main defenses to stop CSRF.
A. Anti-CSRF Tokens (The Gold Standard)
The server generates a cryptographically strong, random token that is tied to the user’s session. This token must be included in every state-changing request (usually as a hidden form field).
Why it works: The attacker cannot read this token because of the Same-Origin Policy (SOP). Without the token, the request is rejected.
B. SameSite Cookies
This browser-level defense restricts when cookies are sent on cross-site requests.
-
Strict: Cookies are never sent on cross-site requests.
-
Lax (Default): Cookies are sent only on top-level navigations (clicking a link), but not on background requests (images, XHR, hidden forms).
-
None: Cookies are sent everywhere (must be
Secure).
C. Referer Validation
The server checks the Referer or Origin header to ensure the request originated from its own domain.
🛠️ 5. Bypassing Defenses: The Sword
Defenses are often implemented incorrectly. Here is how we break them.
1️⃣ Token Validation Logic Flaws
-
Change Method: The server checks tokens on
POSTbut skips the check if you switch toGET. -
Remove Token: The server validates the token if it is present. If you delete the parameter entirely, it skips validation.
-
Token Pooling: The server accepts any valid token from its pool, not just the one tied to your session. An attacker can log in, get a token, and feed it to the victim.
2️⃣ Referer Bypasses
-
Empty Referer: Some servers allow the request if the header is missing. We can use
<meta name="referrer" content="never">to strip it. -
Weak Regex: The server checks if the domain exists somewhere in the string.
attacker.com/?vulnerable-website.compasses the check.
3️⃣ SameSite Bypasses
-
Lax via Method Override: If
SameSite=Laxblocks POST but allows GET, we can useGET /update?_method=POSTto trick the framework. -
The 2-Minute Window: In Chrome, a newly issued cookie is exempt from
SameSite=Laxfor 120 seconds. An attacker can force a cookie refresh (e.g., trigger a login) and then immediately attack. -
On-Site Gadgets: If the target site has an open redirect, we can use it to “bounce” the victim. The request goes
Attacker -> Target Redirect (SameSite) -> Target Action. Since the redirect happens on the target domain, it is treated as a same-site request.
❓ 6. Interview Corner: Common FAQs (Pentest & AppSec)
If you are interviewing for AppSec, expect these CSRF questions.
Q1: What is the difference between CSRF and XSS?
Answer:
-
XSS (Cross-Site Scripting): The attacker injects code (JavaScript) into the application. This code runs in the user’s browser and can read data (like cookies/tokens).
-
CSRF (Cross-Site Request Forgery): The attacker tricks the browser into sending a request. The attacker cannot read the response due to SOP, but they can perform actions (state changes) blindly.
Q2: Why is the SameSite cookie attribute not a silver bullet?
Answer:
-
Legacy Browsers: Not all browsers support it.
-
Top-Level Navigation:
SameSite=Laxstill allows GET requests if they change the URL bar. If the app allows sensitive actions via GET, it is vulnerable. -
Gadget Chains: Client-side redirects or “sibling domains” can be used to convert a cross-site request into a same-site request, bypassing the restriction.
Q3: Describe the “Double Submit Cookie” defense. What is its weakness?
Answer:
Defense: The server sends a random value in a cookie and expects the same value in a request parameter. It checks if Cookie Value == Body Value. It works because an attacker cannot write cookies to the target domain.
Weakness: If the attacker finds any subdomain with a vulnerability (like CRLF injection or XSS) that allows writing cookies (Set-Cookie), they can overwrite the CSRF cookie with a known value and bypass the check.
Q4: If I have a JSON API, am I safe from CSRF?
Answer:
Not automatically.
-
CORS: If CORS is misconfigured (
Access-Control-Allow-Origin: *), an attacker can read the response. -
Simple Requests: An attacker can use a standard HTML form to send JSON data using
enctype="text/plain". The body will look like{"foo":"bar"}=. If the backend parser is lenient (ignores the trailing=), the CSRF succeeds. -
Flash/Java: Historically, plugins could send custom headers.
Q5: What is Referrer-Policy: unsafe-url and why do exploiters use it?
Answer:
Modern browsers strip the path and query string from the Referer header during cross-origin requests for privacy. This breaks exploits that rely on bypassing regex checks (e.g., attacker.com/?target.com). Setting Referrer-Policy: unsafe-url forces the browser to send the full URL, enabling the regex bypass.
Q6: How does the Origin header differ from Referer, and which is better for CSRF protection?
Answer:
-
Referer: Contains the full URL of the previous page (can be stripped for privacy). -
Origin: Contains only the domain protocol and port (e.g.,https://example.com), and is sent specifically for POST requests. -
Protection:
Originis generally preferred for CSRF checks because it respects privacy (no path leakage) and is harder to spoof or suppress thanReferer.
Q7: What is “Login CSRF” and why does it matter?
Answer:
Login CSRF attacks force a victim to log in to the attacker’s account on a website.
- Impact: The victim browses the site thinking they are on their own account. They might enter credit card details or search history, which is then saved to the attacker’s account profile, allowing the attacker to harvest the data later.
Q8: Does a “Preflight” CORS request prevent CSRF?
Answer:
Ideally, yes. If a request requires a custom header (like X-Requested-With or Content-Type: application/json), the browser sends an OPTIONS (preflight) request first. If the server is secure, it won’t allow the attacker’s origin. However, if the server logic allows “Simple Requests” (text/plain, multipart/form-data) or misconfigures CORS, CSRF is still possible.
Q9: Can SameSite=Lax be bypassed using “Method Override”?
Answer:
Yes. Some frameworks (like Laravel or Rails) support method overriding via a query parameter (e.g., ?_method=POST) or a hidden form field. Since SameSite=Lax allows cookies on top-level GET requests, an attacker can construct a malicious link that looks like a GET request but is interpreted by the server as a POST state-changing action.
Q10: How does the __Host- cookie prefix help against CSRF?
Answer:
The __Host- prefix (e.g., __Host-session) forces the browser to only accept the cookie if it is set with the Secure attribute, comes from a secure origin, and has no Domain attribute (meaning it can’t be set by subdomains). This prevents “Cookie Tossing” attacks where an attacker on a subdomain overwrites the session cookie of the main domain to bypass Double Submit defenses.
🎭 7. Scenario-Based Questions
🎭 Scenario 1: The “Login” CSRF
Context: You found a Login form vulnerable to CSRF. You can force a user to log in as your attacker account. Is this a vulnerability?
The Question: How would you weaponize this?
The “Hired” Answer:
“Yes, this is Login CSRF.
-
I force the victim to log in to my account.
-
The victim continues browsing, thinking they are on their own account.
-
They enter sensitive data (credit card, personal info), which is now saved to my account profile.
-
I log in later and harvest their data.”
🎭 Scenario 2: The “Refresh” Gadget
Context: The target uses SameSite=Lax. You found a “Social Login” button that refreshes the session cookie when clicked.
The Question: How do you exploit a POST-based CSRF here?
The “Hired” Answer:
“I would use the Cookie Refresh Bypass.
-
My exploit script creates a popup or uses
window.opento trigger the Social Login flow. -
This forces the server to issue a new session cookie.
-
Chrome allows a 2-minute exception for new cookies, treating them as
Laxbut allowing POSTs. -
My script waits 5 seconds for the login to complete, then auto-submits the malicious form. The ‘fresh’ cookie is sent, bypassing the Lax restriction.”
🎭 Scenario 3: The “Localhost” Developer
Context: A developer argues: “We don’t need CSRF tokens because our API validates the Content-Type: application/json header. HTML forms can’t send that.”
The Question: Is he right?
The “Hired” Answer:
“He is relying on a flimsy defense.
-
Flash/SWF: Historically bypassed this.
-
Navigator.sendBeacon: Can send blobs.
-
The Real Risk: Even if I can’t send that exact header, if I can find an XSS vulnerability anywhere on a subdomain, I can use that XSS to make an authenticated
fetch()request with any headers I want, bypassing the check entirely.”
🎭 Scenario 4: The Open Redirect Chain
Context: You are targeting bank.com. It has strict SameSite=Strict cookies and checks Referer headers. You found an open redirect on bank.com/redirect?url=….
The Question: How can you exploit CSRF here?
The “Hired” Answer:
“I would chain the Open Redirect to bypass the SameSite restriction.
-
I send the victim a link:
bank.com/redirect?url=bank.com/transfer?amount=1000. -
The victim clicks. The initial request is to
bank.com, so it is ‘Same-Site’ relative to the redirect script (or if coming from email, the redirect makes the second hop Same-Site). -
The browser follows the redirect to the transfer page. Since the redirect happens on
bank.com, the browser treats the final request as Same-Site and attaches the Strict cookies.”
🎭 Scenario 5: Sibling Domain Attack
Context: You are auditing main-app.com. It is secure. However, blog.main-app.com is vulnerable to XSS. Both share the same root domain.
The Question: Can you attack the secure main app?
The “Hired” Answer:
“Yes. SameSite treats subdomains as the “Same Site” (e.g., *.main-app.com).
-
I use the XSS on the blog subdomain to execute JavaScript.
-
The script makes a
fetch('https://main-app.com/api/delete_user', {credentials: 'include'})request. -
Even if
main-app.comusesSameSite=Strict, the browser sends the cookies because the request originates from a subdomain of the same site.”
🛑 Summary of Part 1
-
Concept: CSRF tricks the browser into sending cookies to a vulnerable app.
-
Flaw: The server trusts the cookie context without verifying the source intent.
-
Attack: We use hidden forms, image tags, and JS to auto-submit requests.
-
Defense: Anti-CSRF Tokens (Session-bound) and Strict SameSite policies.