Skip to main content

Cross-Site Request Forgery Cheat Sheet

The Cross-Site Request Forgery (CSRF) Cheat Sheet is a flowchart that is designed to cover the common scenarios that an experienced application penetration tester would test for in CSRF testing. It should be most useful for newer penetration testers who don’t have a comprehensive understanding of CSRF testing, although it should also be helpful for experienced penetration testers to have a mental map and a sanity check when looking for CSRF. It should also be useful for developers to see if their application is vulnerable, although that is not who this is designed for. If you are a developer, I highly recommend researching your framework to find a trusted solution if at all possible, rather than engineering your own solution.

This flowchart is not designed to cover every possible edge-case scenario (e.g. attacks that require out-of-date Flash). In theory, there are limitless ways a developer can make mistakes that would lead to CSRF.

Note: You will probably want to open this image in a new tab.

Proof-of-Concept Attacks

HTML GET – Requiring User Interaction for Proof-of-Concept

HTML GET (No User Interaction)

HTML POST – Requiring User Interaction for Proof-of-Concept

HTML POST (AutoSubmit – No User Interaction)

JSON GET – Simple Request

JSON POST – Simple Request

JSON POST – Complex Request

A couple things worth noting


It’s important to note that you do not need to be able to read the response to execute CSRF (this is always the case with basic HTML CSRF). CORS restrictions may mislead people into thinking it is not vulnerable, when it actually is vulnerable to simple requests.

An XMLHTTPRequest is deemed “simple” if it meets certain conditions about the headers that are set. Specifically, it must use GET, HEAD, or POST and the content type can only be set to application/x-www-form-urlencoded, multipart/form-data, or text/plain. The other headers that can be set while keeping the request simple are Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, and Pragma. If it is not deemed simple, it will be pre-flighted with an OPTIONS request to see if the current domain is allowed. By default, XMLHttpRequest will not send credentials, and this must be enabled by setting .withCredentials to true;


Previously, Flash could be used to set custom headers. This only works with old versions of Flash, and used to be exploitable using CSRF-Request-Builder. Today, you would need the site to use crossdomain.xml that allows a domain you can forge requests from.


Today, you would need the site to use a clientaccesspolicy.xml or crossdomain.xml that allows a domain you can forge requests from.


I’ll keep updating and improving this page, but if you have feedback on how we can improve this and make it more useful, we’d love to hear it. Please send us a message using the “contact us” page, leave a comment here, or successfully guess one of our email addresses.

Alex Lauerman

Alex is a penetration tester based in Overland Park, Kansas, which is a suburb of Kansas City. Alex is thankful for being able to spend over 15 years of his life building and breaking applications.