The Wordfence Threat Intelligence team disclosed two vulnerabilities in the Gutenberg Template Library & Redux Framework plugin, which is installed on over 1 million WordPress sites.

One vulnerability allowed users with lower permissions, such as contributors, to install and activate arbitrary plugins and delete any post or page via the REST API. A second vulnerability allowed unauthenticated attackers to access potentially sensitive information about a site’s configuration.

The Gutenberg Template Library & Redux Framework plugin allows site owners to add blocks and block templates to extend the functionality of a site by choosing them from a library. In order to do this, it uses the WordPress REST API to process requests to list and install available blocks, manage existing blocks, and more.

While the REST API Endpoints registered under the redux/v1/templates/ REST Route used a permission_callback to verify a user’s permissions, this callback only checked whether or not the user sending the request had the edit_posts capability. Users with lower permissions that should not be fully trusted for the implemented functionality, such as contributors and authors, have this capability.

This made it possible for a contributor to install not only block templates but any plugin in the WordPress repository via the redux/v1/templates/plugin-install endpoint, though only plugins where the main file matched certain criteria would be successfully activated. While this could not be used directly to take over a site, an attacker could use this functionality to install and activate a vulnerable plugin or combination of plugins and use it to gain further access.

It was also possible for a contributor-level user to delete any post or page using the redux/v1/templates/delete_saved_block endpoint. Additional endpoints registered under this REST route also allowed license management for the Redux plugin, which lower-privileged users should not be able to access.

The Gutenberg Template Library & Redux Framework plugin registered several AJAX actions available to unauthenticated users in the includes function in redux-core/class-redux-core.php that were unique to a given site but deterministic and predictable.

One of these, the $hash_arg, was based on an md5 hash of the site’s URL with a known “salt” of “-redux”. For instance, a site with the URL of ‘http://examplesite[.]com/’ would have a $hash_arg of “901804a230b5e6399d82dcd782395849”, and thus an AJAX action of wp_ajax_nopriv_901804a230b5e6399d82dcd782395849 would be registered on that site

$support_hash = md5( md5( Redux_Functions_Ex::hash_key() . '-redux' ) . '-support' );
add_action( 'wp_ajax_nopriv_' . $support_hash, array( 'Redux_Helpers', 'support_args' ) );
add_action( 'wp_ajax_' . $support_hash, array( 'Redux_Helpers', 'support_args' ) );
$hash_arg = md5( trailingslashit( network_site_url() ) . '-redux' );
add_action( 'wp_ajax_nopriv_' . $hash_arg, array( 'Redux_Helpers', 'hash_arg' ) );
add_action( 'wp_ajax_' . $hash_arg, array( 'Redux_Helpers', 'hash_arg' ) );
add_action( 'wp_ajax_redux_support_hash', array( 'Redux_Functions', 'support_hash' ) );

Sending an AJAX request with this action resulted in a response containing a second hash.

public static function hash_arg() {
    echo esc_html( md5( Redux_Functions_Ex::hash_key() . '-redux' ) );

Based on this, it was possible to determine what the $support_hash for a site would be by taking the hash returned in the response from the $hash_arg AJAX action, appending “-support” as a “salt” and taking the md5 hash of that value.

This $support_hash AJAX action, which was also available to unauthenticated users, called the support_args function in redux-core/inc/classes/class-redux-helpers.php, which returned potentially sensitive information such as the PHP version, active plugins on the site and their versions, and an unsalted md5 hash of the site’s AUTH_KEY and SECURE_AUTH_KEY.

This would be most useful in cases where a separate plugin with an additional vulnerability was installed, as an attacker could use the information to save time and plan an intrusion.

We strongly recommend that all users update to the latest version of the plugin, 4.2.14 as of this writing, as soon as possible. If you know of any friends or colleagues who are using this plugin, we encourage you to share this article with them.