Wordfence and WordPress Miss That Insecure Code in WordPress Plugin is Still Insecure
One of the reasons why WordPress plugins continue to be so insecure is that unethical security providers don’t do basic vetting work before claiming that vulnerabilities exist and that they have been fixed. Unsurprisingly, they don’t show the work, as it were, as to how they came to claim there was a vulnerability. That often leads to real security issues and vulnerabilities remaining in plugins after they take credit for them being fixed. That was the case recently with a situation that involved one of those unethical providers, Wordfence, and WordPress.
Last week, our monitoring systems flag the possibility of a vulnerability in the plugin WPMasterToolKit. At the time, the plugin was closed on the WordPress Plugin Directory. The reason for the closure appears to be a claim by Wordfence of a vulnerability in the plugin. The author of the plugin stated:
If you’re using the plugin, it’s the File Manager module that has this vulnerability. But to exploit this vulnerability, you already need to be an administrator on WordPress.
That matches up with a claim by Wordfence:
The WPMasterToolKit (WPMTK) – All in one plugin plugin for WordPress is vulnerable to Directory Traversal in all versions up to, and including, 2.5.2. This makes it possible for authenticated attackers, with Administrator-level access and above, to read and modify the contents of arbitrary files on the server, which can contain sensitive information.
It turns out what our systems warned us about was related to that. What we immediately noticed is that the code Wordfence was claiming was vulnerable and the code we were checking are not actually restricted to Administrators. If Wordfence had shown their work, it would be easy to see that, but they didn’t.
The plugin was subsequently reopened without the insecurity being properly addressed. That means the team running the WordPress Plugin Directory didn’t properly vet this either. That shouldn’t come as a surprise considering their track record and their hostility towards those trying to work with them address that.
We have reached out to the developer about that and offered to help them address it. For everyone else’s edification, let’s see what is going on here.
While Wordfence didn’t provide even basic details, the code in question exists in the function handle_actions() in the file /admin/modules/core/class-file-manager.php. That is confirmed by the changes that were made to the plugin. Looking at the latest version of the plugin, what you see is that code doesn’t include a capability check to limit access:
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | private function handle_actions() { global $wp_filesystem; if ( ! function_exists( 'WP_Filesystem' ) ) { require_once ABSPATH . 'wp-admin/includes/file.php'; } WP_Filesystem(); $this->set_global_variables(); switch (true) { case isset( $_POST['ajax'], $_POST['token'] ) && isset( $_POST['type'] ): $nonce = sanitize_text_field( wp_unslash( $_POST['token'] ?? '' ) ); if ( ! wp_verify_nonce( $nonce, $this->user_nonce ) ) { header( 'HTTP/1.0 401 Unauthorized' ); die( esc_html__( 'Invalid token', 'wpmastertoolkit' ) ); } // Search if ( $_POST['type'] == "search" ) { $dir = sanitize_text_field( wp_unslash( $_POST['path'] ?? '' ) ) == "." ? '' : sanitize_text_field( wp_unslash( $_POST['path'] ?? '' ) ); $response = $this->scan( $this->fm_clean_path( $dir ), sanitize_text_field( wp_unslash( $_POST['content'] ?? '' ) ) ); echo json_encode($response); exit(); } // Save editor file if ( $_POST['type'] == "save" ) { if ( ! is_dir( $this->PATH ) ) { wp_safe_redirect( $this->FM_SELF_URL . '?page=wp-mastertoolkit-settings-file-manager&p=' ); exit; } $file = sanitize_text_field( wp_unslash( $_GET['edit'] ?? '' ) ); |
There is a nonce check included for the portion of the code shown there, which would normally limit access to it to only users with a valid nonce.
Other portions don’t include that nonce check, so anyone can access it if they can access the function. For example, this portion of the code that allows renaming a file doesn’t include a nonce check:
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 | case isset( $_GET['copy'], $_GET['finish'] ): $copy = urldecode( sanitize_text_field( wp_unslash( $_GET['copy'] ) ) ); $copy = $this->fm_clean_path( $copy ); if ( $copy == '' ) { $this->set_notice( __( 'Source path not defined', 'wpmastertoolkit' ) ); wp_safe_redirect( $this->FM_SELF_URL . '?page=wp-mastertoolkit-settings-file-manager&p=' . urlencode( $this->FM_PATH ) ); exit; } $from = $this->FM_ROOT_PATH . '/' . $copy; $dest = $this->FM_ROOT_PATH; if ( $this->FM_PATH != '' ) { $dest .= '/' . $this->FM_PATH; } $dest .= '/' . basename( $from ); $move = isset( $_GET['move'] ) ? sanitize_text_field( wp_unslash( $_GET['move'] ) ) : ''; $move = $this->fm_clean_path( urldecode( $move ) ); if ( $from != $dest ) { $msg_from = trim( $this->FM_PATH . '/' . basename( $from ), '/' ); if ( $move ) { $rename = $this->fm_rename( $from, $dest ); |
Who has access to the function? Anyone. That is despite only Administrators being intended to have access. The reason that is the case can be seen by looking at the code that Wordfence didn’t show people. The function handle_actions() gets called by the function class_init() if the URL parameter “page” is set to “wp-mastertoolkit-settings-file-manager”:
55 56 57 58 59 60 61 62 63 64 65 66 67 68 | public function class_init() { $this->header_title = esc_html__( 'File Manager', 'wpmastertoolkit' ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( ! isset( $_GET['page'] ) || $_GET['page'] != 'wp-mastertoolkit-settings-file-manager' ) { return; } if ( ! headers_sent() && ! session_id() ) { session_start(); } $this->handle_actions(); |
That gets called during “init” so it runs when accessing any WordPress page:
44 | add_action( 'init', array( $this, 'class_init' ) ); |
So anyone can access the code by simply appending “?page=wp-mastertoolkit-settings-file-manager” to the URL of the homepage of a website using the plugin.
There is an additional condition for the code to be accessible that Wordfence neglected to mention for some reason. The plugin’s File Manager module has to be enabled. It is disabled by default.