Listen:

Patchstack Weekly, Week 12: Secure WordPress File Uploads

Published 21 March 2022
Updated 20 July 2023
Robert Rowley
Author at Patchstack
Table of Contents

Welcome back to the Patchstack Weekly Security Update! This update is for week 12 of 2022 and this week we'll talk about WordPress vulnerabilities and WordPress file uploads.

This week in WordPress-related vulnerabilities, I will talk about 3 plugins that have each been patched due to high-risk security bugs found in their code.

I will also provide an update on the insecure Freemius library situation, and share some possible expectations for what will happen in the next few weeks.

I will then talk about defensive coding strategies for a common security bug in this week's knowledge share. A serious security bug we saw a lot of in WordPress themes in 2021 according to our whitepaper: arbitrary file upload.

Vulnerability news

Stop Bad Bots <= 6.92 - Unauthenticated SQL Injection

wordpress file uploads

Users of the Stop Bad Bots plugin need to update as soon as possible. We wouldn't want any bad bots access to injecting arbitrary SQL commands in the database.

Library File Manager <= 5.2.2 - Arbitrary File Creation/Upload/Deletion

Of course, file management plugins should have the functionality to upload and delete files. But you do not want subscriber users uploading or deleting files on your websites. Unfortunately, there is no update available for this security bug at this time, so you may wish to remove this plugin and look for an alternative.

Responsive Menu <= 4.1.7 - Nonce token leak leading to arbitrary file upload, theme deletion, plugin settings change

Responsive Menu

Finally, users of the Responsive Menu plugin should update soon. The developers patched a bug where a sensitive nonce token gets leaked, allowing subscriber users who can get this sensitive nonce token to go on and upload or delete files, themes, or plugin settings on the website.

This vulnerability was found and reported by Patchstack's own CTO, Dave. Finding and reporting security bugs with his spare time is something anyone can pick up for fun or skill-building.

Freemius Update

Finally, let's talk about Freemius. I got an update from Dave on Friday. He let me know there was an uptick in plugins updating Freemius in the last two weeks, we can see more than 380 plugins have updated to the secured version of Freemius.

This may seem like good news, but I have to share some bad news as well: This is close to, but not yet, halfway there. There remain around 450 plugins still running older insecure versions of Freemius.

So, what happens if these plugins don't get updated? Well, I suspect they will be considered abandoned projects and will be removed from their repositories.

Site owners will not have an option to update these plugins and will need to work on finding replacements. Knowing if your site(s) are running one of these affected plugins is something the Patchstack plugin can help you with.

Weekly knowledge

Secure WordPress file uploads

Depending on a theme or plugin's purpose, you very well may have a requirement to allow users to upload images or other content. Today, I will briefly cover how you can code defensively when adding file upload functionality to your WordPress-related theme or plugin.

Looking at existing code, how previous developers tackled a problem, is a great practice to have, and that is what I will do today.

Let us look over how WordPress core handles file uploads. I found the wp_ajax_upload_attachment() function which has the defensive coding logic in it, I will walk through the code with you here so we can learn together.

Right at the top of the function are two excellent starter security checks:

First, they use check_ajax_referer() which does some nonce checking and extra steps to protect against CSRF style attacks. I've talked about nonce checks previously, so I won't get into those now.

 check_ajax_referer( 'media-form' );

Immediately after that, they make sure the currently logged-in user can upload files using the current_user_can() function. If this is false, they send an error response and bail out of the process.

if ( ! current_user_can( 'upload_files' ) ) { ... }

There are some further authorization checks for editing blog posts. I will skip those, but they are great, always be nuanced with authorization if you can.

Now they have some logic for headers and background images, within this they use a set of special WordPress-only functions to verify the file being uploaded is in fact the image types they wish to accept.

This is done with wp_check_filetype_and_ext() which inspects the data in the file, letting us know for sure it is an image file and then pass it to wp_match_mime_types() which checks if the file type is allowed to be uploaded to the WordPress site.

These two functions are important to use together and are better than just checking the file's name. Because nothing is stopping anyone from renaming a file.

You can think of this defensive code sort of like the bouncers at a club, wp_check_filetype_and_ext() and wp_match_mime_types() are used to verify that the file being uploaded is on the approved file list and can be let in.

At this point, the code has verified the user is authorized to upload files, checked that the request is from the media upload form to protect against CSRF, and finally made sure the file's name and contents are allowed to be uploaded to the site. So the file is approved for upload, and that is what the code goes on to do. We're done!

wordpress file uploads State of WordPress Security 2021

What if you needed to allow a new file type?

Before I go though, I want to talk about that approved file types list. By default WordPress only accepts safe to upload file types (these include images, videos, documents, and some code) but what if you needed to allow a new file type?

If that is the case, you will need to do some additional research. Because some filetypes have security or privacy considerations that you will want to take into consideration.

File-specific attack examples could be something like a compressed file being very small to upload, but when de-compressed it takes up excessive disk space. Or an attack like XML expansion (where the file has internal references that consume a large amount of RAM or other resources, leading to DoS).

Or, perhaps you wish to protect user privacy by removing sensitive data located in an image or document's headers. Even I forget that every image taken with a smartphone has GPS location tagged in it, and documents saved in some formats include details about my computer.

The good news is, you likely do not need to write the defensive code yourself. If you research enough, you may find another developer already wrote the code and released it open source to help everyone out.

One great example is the team at 10up, who released safe-svg. This is a WordPress-specific library as a plugin, which will help you safely handle SVG file uploads.

I would recommend you take a look at the source code of safe-svg.php as a starting point to see how they added the additional acceptable file type, sanitized the SVG file's content against some common SVG specific security bugs, and fixed some bugs related to SVG thumbnails in the WordPress dashboard.

Thanks and appreciation

This week's thanks go out to the developers of the Stop Bad Bots and Responsive Menu plugins for patching those security bugs this week.

A wide-reaching thank you is extended to all of the developers out there updating the versions of Freemius in their code. Keep it up! And thank you to the WP.org plugins team for reaching out to the hundreds of developers affected, informing them of the need to update Freemius.

And a special thank you to the 10up team, who open-sourced the useful safe-SVG code for everyone to use. This is an example of the great power of open-source, and we need more development teams like you who are not afraid to help everyone.

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

The latest in Patchstack News

Looks like your browser is blocking our support chat widget. Turn off adblockers and reload the page.
crossmenu