Updated: 20-01-22

Patchstack Weekly, Week 03: WordPress Vulnerabilities & Cross-Site Request Forgery

Robert Rowley
from patchstack

Welcome back to the Patchstack Weekly security update. It is the third week of 2022 and this episode is called WordPress vulnerabilities & Cross-Site Request Forgery.

Within this session, I will inform you of 6 popular open-source WordPress components that have patched various vulnerabilities in their code, from information disclosure to cross-site scripting and cross-site request forgery.

In this week's knowledge share, I will discuss cross-site request forgery vulnerabilities, what their risks are, and share an easy fix for it using nonces.

Vulnerability news

Users of the WP Import Export and WP Import Export Lite plugins should update to the most recent release. The plugin author has patched a sensitive data disclosure vulnerability in both versions of this plugin, which could allow unauthenticated users to download the previously exported data sets.

WP Import Export premium plugin <= 3.9.15 - Unauthenticated Sensitive Data Disclosure
WP Import Export Lite plugin <= 3.9.15 - Unauthenticated Sensitive Data Disclosure

There were two plugins that patched an unauthenticated Cross-Site Scripting (XSS) vulnerability in them in the last week as well.

Users of CF7 Store to DB Lite and WP HTML Mail plugins should update to the most recent release. We do not want anyone to find out arbitrary HTML has been injected on their websites, so it's an important patch to get done.

Form Store to DB (cf7-store-to-db-lite) plugin <= 1.1.0 - Unauthenticated Stored Cross-Site Scripting (XSS)
WP HTML Mail (wp-html-mail) plugin <= 3.0.9 - Unauthenticated Stored Cross-Site Scripting (XSS) 

Finally, there were two additional plugins that patched Cross-Site Request Forgery or CSRF vulnerabilities in them this week as well.

Users of the Easy Login WooCommerce and Side Cart Woocommerce plugins should update these plugins as soon as they have a chance.

Login/Signup Popup (easy-login-woocommerce) plugin <= 2.2 - Cross-Site Request Forgery (CSRF) vulnerability leading to Arbitrary Options Update
Side Cart Woocommerce (side-cart-woocommerce) plugin <= 2.0 - Cross-Site Request Forgery (CSRF) vulnerability leading to Arbitrary Options Update

CSRF is an interesting vulnerability that does not get a lot of attention like the more popular XSS or SQLi vulnerabilities. So, CSRF will be the topic of this week's knowledge share, let's get into it.

Weekly knowledge

In this weeks' knowledge share, we are going to participate in a tradition going back thousands of years in Human history. Since the days before society and cities, humanity faced threats of attack. Attacks like animals raiding our villages, huts or caves, or other human tribes plundering precious resources.

This naturally leads to clever humans designing defenses against these threats. I am no historian, but I am certain these first defenses would be something like surrounding the communal village with a fence, then as threats changed, we turned out villages into towns and fortresses.

Cross-Site Request Forgery

Thousands of years later … we have modern-day web applications and the same game of attack and defense is being played. We can look at it as a game as well, have fun understanding the attacks, and learn from them to build our defenses.

So, I will first explain the attack (CSRF) and then the defense. Luckily, just two functions are needed in your code to build a proper defense.

What is CSRF?

CSRF stands for cross-site request forgery. This attack requires an attacker (or compromised website the attacker controls) to trick a logged-in user (or really the user's browser) to request a URL that performs a privileged action on a website as that logged-in user.

This sort of vulnerability sounds a little far-fetched, especially if you're thinking that attackers are politely asking admin users to "log in to your website and visit this URL please". That is certainly possible, but highly implausible. The more common scenario where a CSRF attack is successful is when it is combined with another vulnerability, like cross-site scripting.

What is the impact?

That depends, and that is because the impact of CSRF is connected to which API endpoint (or AJAX endpoints for WordPress) lacks the proper protections. The more serious the unprotected endpoint's action is, the more serious the CSRF's impact can be.

What is the risk?

Like I mentioned earlier, you do not want to think of CSRF as an independent vulnerability. Instead consider the potential when CSRF is combined with another vulnerability, like Cross-Site Scripting (XSS).

Cross-Site Request Forgery

Attackers can exploit an XSS vulnerability which would allow them to inject arbitrary HTML onto pages on the target website. This is pretty bad on its own, but, combine that XSS with CSRF, and suddenly one visit to the wrong URL (that contains an injected XSS payload) leads to the user's logged-in browser making requests for privileged API actions on the back end without the user's knowledge.

So, how do we protect against cross-site request forgery?

WordPress core added a feature called a "nonce", which stands for a number used once. However, the implementation is not "used once" it is a temporary validation token, which is good for between 12 and 24 hours.

The implementation in code is simple, you first generate a nonce and share it with the browser (typically via a GET or POST variable). Then, elsewhere in the code that performs a high-privileged action, you check for the nonce's existence or validity during the time frame.

Let's get more practical with an example, let's say we are developing a WordPress plugin, and have an AJAX endpoint that cancels and refunds an order. This feature is needed because it saves a lot of time and headache for site admins. So you write the AJAX endpoint, it accepts an Order ID number and performs all the backend work needed to cancel and refund the related order.

You remember the importance of checking if the user is authorized or not. I talked about this just 2 weeks ago on the Patchstack Weekly. So you add a current_user_can() conditional, right at the start of the endpoint's function.

if ( current_user_can('refund_orders') ) {
# Then, do the stuff
} else {
die('Current user is not Authorized to refund orders');

If a current user can refund orders, then do the stuff. Else die (or exit the process) with a message that the "current user is not authorized to refund orders". Easy enough. But, it lacks CSRF protection, so let's add some.

First, on the page that generates the "button" for order cancellation/refunds, we create the temporary nonce value. We use wp_create_nonce() for this, and pass it a string to name the nonce. wp_create_nonce returns a string, which is the value of the nonce which will be valid for the next 12 to 24 hours. We save this nonce value as a variable which we pass along to the browser via a hidden field in the form of the request.

$refund_nonce = wp_create_nonce('refund-order');

< input type=hidden name='refund_nonce' value='<? echo $refund_nonce; ?>'>
< input type=button name='refund_action' value='Issue Refund'>

Now, we can verify the nonce in the AJAX endpoint function, ideally right along with the authorization checks. This is done by using the wp_verify_nonce() function, we pass it the value of the nonce from the browser and the name of the nonce we are checking against. If wp_verify_nonce() returns true, then we are good to go, otherwise, we bail out and end the process.

if( isset($_POST['refund_nonce'])
&& wp_verify_nonce($_POST['refund_nonce'], 'refund-order')
&& current_user_can('refund_orders']) ) {
# Then, do stuff
} else {
die('Unauthorized Action');

You can learn more about WordPress nonces are the WordPress developer pages linked above, including how to change that 12 to 24-hour time window to a shorter time frame.

I hope the information I have shared here is helpful though and shows you that nonces are easy to implement and it only takes a few lines of code to protect against CSRF attacks.

Thanks and appreciation

This week's thanks go out to the WordPress core team for including these helpful functions to produce and validate time-frame-based nonces and thank you to the documentation team who wrote the great resources I used as references for the how-to-nonce guide above.

Further thanks go out to the developers and designers who patched security bugs in the components this week, and to the bug bounty hunters finding and reporting these bugs before the bad actors do. Together, you are making the open-source web a more secure place and are owed a debt of gratitude for your efforts.

And a thank you to any WordPress developer out there that caught this episode and now knows how to properly protect your AJAX endpoints. Now, it is up to you to use this knowledge to write more secure code.

I will be back next week with more security tips, tricks, opinions, and news on the Patchstack Weekly security update!

Thank you for your time.

Share This Article
Related Articles