WordPress CSRF Exploit Draft Status WordPress CSRF Exploit Draft Status wordpress wordpress

WordPress CSRF Exploit Draft Status


WordPress already provides a CSRF protection mechanism by using a nonce. When creating a new post, a new unique nonce is created. This nonce is required and must be submitted with the rest of the POST data in order for the post to be saved as a draft or be published. If the nonce is not present or invalid, the request is rejected. (Tested with Wordpress v4.9.8)

In your tests you were able to modify the draft because you submitted the correct nonce using Burp, but in a CSRF attack this value would be unknown. Burp is an intercepting proxy, so you practically performed a MITM attack on your own HTTP traffic. If you're concerned about MITM attacks you should use HTTPS. Of course an attacker could still intercept your network traffic, but all the data would be encrypted.

So, I wouldn't say that this is a CSRF exploit, but a MITM exploit. You can protect your WordPress installation from most public exploits by keeping your WordPress version, plugins and thems updated, and also you can find many security related plugins in https://wordpress.org/plugins/tags/security/.

I think the best tool for security tests on WordPress is WPScan. It has a huge database of vulnerabilities and it can detect possible exploits and enumerate users, version and plugins. WPScan is mostly a recon tool, but we can test if the reported vulnerabilities are exploitable with Metasploit or Wpxf, a less known but powerful tool that is specialized on WordPress exploitation. Note that those tools can only detect and exploit public exploits. If you want to discover new vulnerabilities then you could use Burp or similar scanners and study the WordPress source code.

If I have misunderstood the question, and you have a form that doesn't have a nonce (let's say you're writting a plugin), you can add a nonce with wp_nonce_field and then verify it in the script that receives the form with wp_verify_nonce. However, if you have a WordPress installation that doesn't use a nonce with its forms, you shouldn't try to add a nonce manually, but update to a newer version.


Wordpress does not use traditional nonces, instead binding them to a specific form action and user session combination, and persisting them for multiple usage over two ticks (default 12 hours each), which means they are by default valid for up to a full day, and may be repeatedly used over that time period, as well as being "refreshed" after a use to reset their time period entirely. This has been consistently criticized for a number of years by security professionals as misleading and insecure, and the WordPress core team has defended their stance by claiming that the requirement that someone has both the user session as well as the actual nonce makes this a negligible threat, although both a compromised host as well as a site that does not have valid ssl protection can make this pretty easy to accomplish.

The underlying issue you are encountering is symptomatic of the fact that a WordPress nonce is not a nonce at all. It is essentially an access control hash used repeatedly for a short duration for a single form action, and has no mechanism in place to insure its single use. This is why you were able to successfully intercept and re-use the nonce. FYI, this behavior can also be recreated pretty easily in Zed Attack Proxy, Wireshark, Charles Proxy, and numerous other similar utilities. Burp is not the only tool that is capable of uncovering this weakness.

You do however have some recourse to correct this if you want, but it is rather involved and not particularly simple to accomplish.

The following functions are pluggable, which means you can override them with your own, and also control the system interpretation of what a nonce is. You will need to provide your own nonce system using these specific methods, and return identical values to the original expected ones so you don't break plugins/core code functionality:

You could, for example, provide your own nonce implementation using a support from a package such as elhardoum/nonce-php or wbswjc/nonce, and then implement it through a custom plugin that overrides the above pluggable functions and uses them as wrappers for your own nonce implementation, although this is not incredibly straightforward and will require a great deal of custom logic to implement.

You will need to not only override the above pluggable functions, but will also need to call apply_filters similarly to their own source, properly nullify whatever changes plugins attempt to make that are bound to those filters, and also return an expected value in the exact same format as the original so you do not disrupt how other plugins/themes you may be using have implemented them.

If you believe that there is sufficient risk, or that the data your site is safeguarding is of sufficient importance, it is likely worth the effort. If you are not handling financial transactions or sensitive data, are properly secured behind ssl, or have no particular interest in writing a custom implementation of nonces and subsequently maintaining it to work around the ways it inevitably breaks numerous plugins who expect the default lax implementation to be present, then you are probably best off taking the core devs at their word and using the defaults, provided you update frequently, have a strong security plugin like wordfence or sucuri, and routinely run updates on all of your plugins/themes.

As an absolute minimum, you pretty much must have SSL in place to mitigate MITM attacks, and should use proper access control headers to mitigate CSRF.