4 Apr 2023

Awesome Motive Isn’t Disclosing They Are Trying (and Sometimes Failing) to Fix Vulnerabilities in Their Plugins

Yesterday, Automattic’s WPScan claimed that the latest version of the 1+ million install WordPress plugin WPCode had fixed a vulnerability:

The plugin has a flawed CSRF when deleting log, and does not ensure that the file to be deleted is inside the expected folder. This could allow attackers to make users with the wpcode_activate_snippets capability delete arbitrary log files on the server, including outside of the blog folders

As that plugin is used by at least one of our customers, we should have already been aware of that vulnerability, as we would already have reviewed the new version based on the mention in the changelog that the issue had been addressed. But we hadn’t. What was going on? Looking at the changelog, we found that there was no disclosure whatsoever. Here is what is listed:

  • New: We redesigned the auto-insert location picker to make it easier to find the right place to insert your snippets.
  • Fix: We fixed an edge-case where a snippet getting automatically deactivated due to throwing an error would have its code changed.
  • Fix: Inserting a snippet as a shortcode was ignoring the conditional logic rules enable toggle and always applying rules.
  • Fix: We updated the way we check the taxonomy term id when applying conditional logic rules.

If there really was a vulnerability being fixed, this wouldn’t be the only recent instance where the developer of the plugin, Awesome Motive, hadn’t disclosed it.

At the end of January, we discussed Awesome Motive not disclosing they had fixed a vulnerability in their 3+ million install MonsterInsights. The importance of disclosure was on display with that, as they didn’t actually fix the vulnerability. If others don’t know a vulnerability has been attempted to be fixed, no one can double check to make sure it has been fixed. With their next attempt to fix it, a month and a half later, they provided a vague disclosure:

Update: We applied additional security hardening.

Once again, though, they hadn’t fixed the vulnerability. Two versions later, they finally fixed it, but they didn’t provide any disclosure of that:

  • New: Our New PPC Tracking addon allows you to effortlessly track sales inside Google Ads, Microsoft Ads, and Meta.
  • Enhancement: We updated and tweaked lots elements to make our dashboard easier to use

What makes all of that more troubling is that Awesome Motives’s chief security officer (CSO) is also the “security reviewer” on the team running the WordPress Plugin Directory.

Cross-Site Request Forgery (CSRF)/File Deletion

WPScan isn’t known for their accuracy, so just because they are claiming a vulnerability exists and has been fixed (as they incorrectly did with the vulnerability in MonsterInsights), it doesn’t mean both or even one of those is true. But in this case, both are accurate.

The vulnerability existed in the function maybe_delete_log() in the file /includes/admin/pages/class-wpcode-admin-page-tools.php, which is made accessible to even those not logged in to WordPress:

67
add_action( 'admin_init', array( $this, 'maybe_delete_log' ) );

As of the previous version, the function included both a capabilities check and a nonce check to restrict access to its functionality:

1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
public function maybe_delete_log() {
 
	// Check nonce.
	if ( isset( $_GET['wpcode_action'] ) && isset( $_GET['_wpnonce'] ) && ! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'wpcode_delete_log' ) ) {
		wp_die( esc_html__( 'Link expired. Please refresh the page and retry.', 'insert-headers-and-footers' ) );
	}
	if ( ! isset( $_GET['wpcode_action'] ) || 'delete_log' !== $_GET['wpcode_action'] || ! isset( $_GET['log'] ) ) {
		return;
	}
 
	if ( ! current_user_can( 'wpcode_activate_snippets' ) ) {
		echo '<p>' . esc_html__( 'You do not have sufficient permissions to delete logs.', 'insert-headers-and-footers' ) . '</p>';
 
		return;
	}

Except the nonce check, which prevents cross-site request forgery (CSRF), is bypassed by simply not providing a nonce to be checked. That was corrected in the new version:

1042
1043
1044
1045
	// Check nonce.
	if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'wpcode_delete_log' ) ) {
		wp_die( esc_html__( 'Link expired. Please refresh the page and retry.', 'insert-headers-and-footers' ) );
	}

The other problem with the code was that user input to specify a log file to be deleted wasn’t using proper sanitization and or validation:

1052
wpcode()->logger->delete_log( sanitize_text_field( wp_unslash( $_GET['log'] ) ) );

The function sanitize_text_field() doesn’t restrict the ability to include input that allows traversing out of the intended directory for the file to be deleted. That was addressed by using the sanitize_key() function instead:

1053
wpcode()->logger->delete_log( sanitize_key( wp_unslash( $_GET['log'] ) ) );

There was also code added to another file to prevent directory traversal before the deletion happens.

So previously, an attacker could cause a logged in Administrator to delete files on a website with the .log extension without the Administrator intending it.

That the code was insecure in both those ways isn’t good. Making this worse, this isn’t code that has long been in the plugin, but code that was introduced in February. So Awesome Motive has a very recent problem with their handling of securing their code.

Leave a Reply

Your email address will not be published.