30 Apr 2025

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.

Leave a Reply

Your email address will not be published.