On March 23, 2020, our Threat Intelligence team discovered 2 vulnerabilities in WordPress SEO Plugin – Rank Math, a WordPress plugin with over 200,000 installations. The most critical vulnerability allowed an unauthenticated attacker to update arbitrary metadata, which included the ability to grant or revoke administrative privileges for any registered user on the site. The second vulnerability allowed an unauthenticated attacker to create redirects from almost any location on the site to any destination of their choice.

We reached out to the plugin’s developer the next day, on March 24, 2020, and received a response within 24 hours. We privately disclosed the full vulnerability details on March 25, 2020, and the plugin developer released a patch on March 26, 2020. We strongly recommend updating to the latest version,, as soon as possible as this is considered a critical security issue.

Wordfence Premium customers received a new firewall rule on March 24, 2020, to protect against exploits targeting this vulnerability. Wordfence users still using the free version will receive the rule after thirty days on April 23, 2020.

WordPress SEO Plugin – Rank Math is a WordPress plugin designed to assist with search engine optimization, and it has a number of features to make doing so easier, including the ability to update metadata on posts. In order to add this feature, the plugin registered a REST-API endpoint, rankmath/v1/updateMeta, which failed to include a permission_callback used for capability checking.

The vulnerable REST route:

				'methods'  => WP_REST_Server::CREATABLE,
				'callback' => [ $this, 'update_metadata' ],
				'args'     => $this->get_update_metadata_args(),

The endpoint called a function, update_metadata which could be used to update the slug on existing posts, or could be used to delete or update metadata for posts, comments, and terms. This endpoint also allowed for updating metadata for users, leading to this critical vulnerability.

The update_metadata function:

	public function update_metadata( WP_REST_Request $request ) {
		$object_id   = $request->get_param( 'objectID' );
		$object_type = $request->get_param( 'objectType' );
		$meta        = $request->get_param( 'meta' );

		$new_slug = true;
		if ( isset( $meta['permalink'] ) && ! empty( $meta['permalink'] ) ) {
			$post     = get_post( $object_id );
			$new_slug = wp_unique_post_slug( $meta['permalink'], $post->ID, $post->post_status, $post->post_type, $post->post_parent );
					'ID'        => $object_id,
					'post_name' => $new_slug,
			unset( $meta['permalink'] );

		$sanitizer = Sanitize::get();
		foreach ( $meta as $meta_key => $meta_value ) {
			if ( empty( $meta_value ) ) {
				delete_metadata( $object_type, $object_id, $meta_key );

			update_metadata( $object_type, $object_id, $meta_key, $sanitizer->sanitize( $meta_key, $meta_value ) );

		return $new_slug;

WordPress user permissions are stored in the usermeta table, which meant that an unauthenticated attacker could grant any registered user administrative privileges by sending a $_POST request to wp-json/rankmath/v1/updateMeta, with an objectID parameter set to the User ID to be modified, an objectType parameter set to user, a meta[wp_user_level] parameter set to 10, and a meta[wp_capabilities][administrator] parameter set to 1.

Alternatively, an attacker could completely revoke an existing administrator’s privileges by sending a similar request with a meta[wp_user_level] parameter and a meta[wp_capabilities] parameter set to empty values. Since many sites have a single administrator with a user ID of 1, this meant that an attacker could lock an administrator out of their own site.

Note that these attacks are only the most critical possibilities. Depending on the other plugins installed on a site, the ability to update post, term, and comment metadata could potentially be used for many other exploits such as Cross-Site Scripting (XSS).

The WordPress SEO Plugin – Rank Math plugin includes a number of optional modules, including a module that can be used to create redirects on a site. In order to add this feature, the plugin registered a REST-API endpoint, rankmath/v1/updateRedirection, which again failed to include a permission_callback for capability checking.

The vulnerable REST route:

				'methods'  => WP_REST_Server::CREATABLE,
				'callback' => [ $this, 'update_redirection' ],

The endpoint called a function, update_redirection, which could be used to create new redirects or modify existing redirects, with an important limitation. The redirect could not be set to an existing file or folder on the server, including the site’s main page. This limited the damage to some extent in that, while an attacker could create a redirect from most locations on the site, including new locations, or any existing post or page other than the homepage, they could not redirect visitors immediately upon accessing the site.

The update_redirection function:

	public function update_redirection( WP_REST_Request $request ) {
		$cmb     = new stdClass;
		$metabox = new RankMathRedirectionsMetabox;

		$cmb->object_id    = $request->get_param( 'objectID' );
		$cmb->data_to_save = [
			'has_redirect'            => $request->get_param( 'hasRedirect' ),
			'redirection_id'          => $request->get_param( 'redirectionID' ),
			'redirection_url_to'      => $request->get_param( 'redirectionUrl' ),
			'redirection_sources'     => str_replace( home_url( '/' ), '', $request->get_param( 'redirectionSources' ) ),
			'redirection_header_code' => $request->get_param( 'redirectionType' ) ? $request->get_param( 'redirectionType' ) : 301,

		if ( false === $request->get_param( 'hasRedirect' ) ) {
			unset( $cmb->data_to_save['redirection_url_to'] );

		if ( empty( $request->get_param( 'redirectionID' ) ) ) {
			unset( $cmb->data_to_save['redirection_id'] );

		return $metabox->save_advanced_meta( $cmb );

In order to perform this attack, an unauthenticated attacker could send a $_POST request to rankmath/v1/updateRedirection with a redirectionUrl parameter set to the location they wanted the redirect to go to, a redirectionSources parameter set to the location to redirect from, and a hasRedirect parameter set to true. This attack could be used to prevent access to all of a site’s existing content, except for the homepage, by redirecting visitors to a malicious site.

Protecting REST-API Endpoints

The REST-API functionality in WordPress provides great flexibility for plugin developers. Of course, with that flexibility comes great responsibility. If your plugin is using the REST-API, make sure to include a permission_callback on any endpoints you don’t want to be available to the public, though be aware this also requires that a valid wp_rest nonce be generated and sent with any requests to the protected endpoint.

Disclosure Timeline

March 23, 2020 – Wordfence Threat Intelligence discovers and analyzes vulnerabilities.
March 24, 2020– Initial contact with the plugin’s developer team. Firewall rule released for Wordfence Premium users.
March 25, 2020 – Plugin developer confirms appropriate inbox for handling discussion. Full vulnerability disclosure sent.
March 26, 2020 – Patched version of plugin released.
April 23, 2020 – Firewall rule becomes available to Wordfence free users.


In today’s post, we discussed 2 vulnerabilities caused by unprotected REST API endpoints in the WordPress SEO Plugin – Rank Math plugin. These vulnerabilities have been fully patched in version 10.0.41, and we strongly recommend that all users of this plugin upgrade to the latest version available immediately. Sites running Wordfence Premium have been protected against these vulnerabilities since March 24, 2020. Sites running the free version of Wordfence will receive the firewall rule update on April 23, 2020.

Special thanks to the developers of WordPress SEO Plugin – Rank Math for their rapid response and exemplary handling of our disclosure.

Source Article