Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : May 21, 2026

CVE-2026-6555: ProSolution WP Client <= 2.0.0 – Unauthenticated Arbitrary File Upload via 'files' (prosolution-wp-client)

CVE ID CVE-2026-6555
Severity Critical (CVSS 9.8)
CWE 434
Vulnerable Version 2.0.0
Patched Version 2.0.1
Disclosed May 18, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-6555:
This vulnerability allows unauthenticated attackers to upload arbitrary files, including PHP shells, to the ProSolution WP Client plugin for WordPress. The flaw exists in versions up to and including 2.0.0. The CVSS score is 9.8, indicating critical severity.

Root Cause:
The vulnerable code resides in `public/class-prosolwpclient-public.php`, specifically in the file upload handler beginning around line 1002. The plugin processes an array of uploaded files passed via the ‘files’ parameter. In the vulnerable version, validation (extension check, MIME type check via `finfo`, image dimension verification) only occurs for the first file in the array, i.e., `$submit_data[‘name’][0]` and `$tmp_fileloc`. However, the upload processing loop (which moves the file from `tmp_name` to the final destination) iterates over all files without re-validating each entry. This means an attacker can supply a benign first file (e.g., a valid PNG) to pass all checks, followed by a malicious `.php` file that bypasses validation but still gets moved to the upload directory.

Exploitation:
An attacker sends a POST request to the vulnerable endpoint (likely an AJAX action or form handler) with the `files` parameter structured as an associative array. The request includes `name[0]` set to a safe file (e.g., `image.png`), `tmp_name[0]` pointing to a valid image, `name[1]` set to `shell.php`, and `tmp_name[1]` pointing to a PHP payload. The plugin only validates index 0, but processes and moves both files to a web-accessible directory, enabling remote code execution by accessing the uploaded PHP file.

Patch Analysis:
The patch wraps all file processing logic inside a `for` loop that iterates through every index in the `name` array (`for ($file_idx = 0; $file_idx < count($submit_data['name']); $file_idx++)`). Inside the loop, the validation (sanitization, extension whitelist, MIME check, image dimension check) is applied to each file individually via the current index (`$submit_data['name'][$file_idx]`, `$submit_data['tmp_name'][$file_idx]`). This ensures that every uploaded file must satisfy all security checks before being moved to the upload directory, closing the bypass.

Impact:
Successful exploitation allows unauthenticated remote code execution on the WordPress server. An attacker can upload a PHP web shell, gain full control over the application, access or modify the database, compromise other sites on shared hosting, and use the server for lateral movement or malicious activities. This is a critical severity vulnerability with potential total compromise.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/prosolution-wp-client/prosolwpclient.php
+++ b/prosolution-wp-client/prosolwpclient.php
@@ -16,7 +16,7 @@
      * Plugin Name:       ProSolution WP Client
      * Plugin URI:        https://prosolution.com/produkte-und-services/workexpert.html
      * Description:       WordPress client for ProSolution
-     * Version:           2.0.0
+     * Version:           2.0.1
      * Author:            ProSolution
      * Author URI:        https://www.prosolution.com
      * License:           GPL-2.0+
@@ -41,7 +41,7 @@


     defined('PROSOLWPCLIENT_PLUGIN_NAME') or define('PROSOLWPCLIENT_PLUGIN_NAME', 'prosolwpclient');
-    defined('PROSOLWPCLIENT_PLUGIN_VERSION') or define('PROSOLWPCLIENT_PLUGIN_VERSION', '2.0.0');
+    defined('PROSOLWPCLIENT_PLUGIN_VERSION') or define('PROSOLWPCLIENT_PLUGIN_VERSION', '2.0.1');
     defined('PROSOLWPCLIENT_BASE_NAME') or define('PROSOLWPCLIENT_BASE_NAME', plugin_basename(__FILE__));
     defined('PROSOLWPCLIENT_ROOT_PATH') or define('PROSOLWPCLIENT_ROOT_PATH', plugin_dir_path(__FILE__));
     defined('PROSOLWPCLIENT_ROOT_URL') or define('PROSOLWPCLIENT_ROOT_URL', plugin_dir_url(__FILE__));
--- a/prosolution-wp-client/public/class-prosolwpclient-public.php
+++ b/prosolution-wp-client/public/class-prosolwpclient-public.php
@@ -1002,62 +1002,64 @@
 				die(__("No file uploaded", "prosolwpclient"));
 			}

-			// get file name and temp file location and sanitize them
-			$org_filename = isset( $submit_data['name'][0] ) ? sanitize_file_name( $submit_data['name'][0] ) : '';
-			$tmp_fileloc = isset( $submit_data['tmp_name'][0] ) ? $submit_data['tmp_name'][0] : '';
-
-			// if file name or location empty, process must be aborted
-			if ( empty( $org_filename ) || empty( $tmp_fileloc ) || ! is_uploaded_file( $tmp_fileloc ) ) {
-				die(__("Invalid file", "prosolwpclient"));
-			}
-			//check file extension for uploaded "up" file
-    		$up_fileext = strtolower( pathinfo( $org_filename, PATHINFO_EXTENSION ) );
+			for ($file_idx = 0; $file_idx < count($submit_data['name']); $file_idx++) {
+				// get file name and temp file location and sanitize them
+				$org_filename = isset( $submit_data['name'][$file_idx] ) ? sanitize_file_name( $submit_data['name'][$file_idx] ) : '';
+				$tmp_fileloc = isset( $submit_data['tmp_name'][$file_idx] ) ? $submit_data['tmp_name'][$file_idx] : '';
+
+				// if file name or location empty, process must be aborted
+				if ( empty( $org_filename ) || empty( $tmp_fileloc ) || ! is_uploaded_file( $tmp_fileloc ) ) {
+					die(__("Invalid file", "prosolwpclient"));
+				}
+				//check file extension for uploaded "up" file
+				$up_fileext = strtolower( pathinfo( $org_filename, PATHINFO_EXTENSION ) );

-			//since most of cv or profile picture are typically using this format, we should whitelist these extension only.
-			//do not use proSol_mimeExt function, it allow all kind of extension including big nono one like php or other programming language.
-			$whitelist_ext = array( 'jpg', 'jpeg', 'png', 'gif', 'webp', 'pdf', 'doc', 'docx' );
-
-			//check extension first
-			if ( ! in_array( $up_fileext, $whitelist_ext, true ) ) {
-				die(__("File type not allowed", "prosolwpclient"));
-			}
+				//since most of cv or profile picture are typically using this format, we should whitelist these extension only.
+				//do not use proSol_mimeExt function, it allow all kind of extension including big nono one like php or other programming language.
+				$whitelist_ext = array( 'jpg', 'jpeg', 'png', 'gif', 'webp', 'pdf', 'doc', 'docx' );
+
+				//check extension first
+				if ( ! in_array( $up_fileext, $whitelist_ext, true ) ) {
+					die(__("File type not allowed", "prosolwpclient"));
+				}

-			//check for REAL mime type, $submit_data['type'] only check for surface-level.
-			$finfoObj = new finfo( FILEINFO_MIME_TYPE );
-			$true_mmime = $finfoObj->file( $tmp_fileloc );
-
-			//syntax below is big nono, don't use it to check mime!!!
-			//$mime_type   = isset( $submit_data['type'] ) ? $submit_data['type'][0] : '';
-			//again do not use prosol_mimeext, they will allow script or programming language
-			//$ext = proSol_mimeExt($mime_type);
-
-			$wp_mime_chk = wp_check_filetype( $org_filename );
-			if ( $wp_mime_chk['type'] == false ) {
-				die(__("File type is not allowed.", "prosolwpclient"));
-			}
+				//check for REAL mime type, $submit_data['type'] only check for surface-level.
+				$finfoObj = new finfo( FILEINFO_MIME_TYPE );
+				$true_mmime = $finfoObj->file( $tmp_fileloc );
+
+				//syntax below is big nono, don't use it to check mime!!!
+				//$mime_type   = isset( $submit_data['type'] ) ? $submit_data['type'][0] : '';
+				//again do not use prosol_mimeext, they will allow script or programming language
+				//$ext = proSol_mimeExt($mime_type);
+
+				$wp_mime_chk = wp_check_filetype( $org_filename );
+				if ( $wp_mime_chk['type'] == false ) {
+					die(__("File type is not allowed.", "prosolwpclient"));
+				}

-			//only listed mimes type are allow
-			$whitelist_mimes = array(
-				'jpg'  => 'image/jpeg',
-				'jpeg' => 'image/jpeg',
-				'png'  => 'image/png',
-				'gif'  => 'image/gif',
-				'webp' => 'image/webp',
-				'pdf'  => 'application/pdf',
-				'doc'  => 'application/msword',
-				'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
-			);
-
-			//check for real hidden mimes type
-			if ( ! isset( $whitelist_mimes[ $up_fileext ] ) || $true_mmime !== $whitelist_mimes[ $up_fileext ] ) {
-				die(__("File content does not match its extension", "prosolwpclient"));
-			}
+				//only listed mimes type are allow
+				$whitelist_mimes = array(
+					'jpg'  => 'image/jpeg',
+					'jpeg' => 'image/jpeg',
+					'png'  => 'image/png',
+					'gif'  => 'image/gif',
+					'webp' => 'image/webp',
+					'pdf'  => 'application/pdf',
+					'doc'  => 'application/msword',
+					'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+				);
+
+				//check for real hidden mimes type
+				if ( ! isset( $whitelist_mimes[ $up_fileext ] ) || $true_mmime !== $whitelist_mimes[ $up_fileext ] ) {
+					die(__("File content does not match its extension", "prosolwpclient"));
+				}

-			if ( in_array( $up_fileext, array( 'jpg', 'jpeg', 'png', 'gif', 'webp' ), true ) ) {
-				//for image upload we can also verified image via dimension size like height and width, fake image file will be false result
-				$img_dimension = @getimagesize( $tmp_fileloc );
-				if ( $img_dimension === false ) {
-					die(__("Invalid image dimension", "prosolwpclient"));
+				if ( in_array( $up_fileext, array( 'jpg', 'jpeg', 'png', 'gif', 'webp' ), true ) ) {
+					//for image upload we can also verified image via dimension size like height and width, fake image file will be false result
+					$img_dimension = @getimagesize( $tmp_fileloc );
+					if ( $img_dimension === false ) {
+						die(__("Invalid image dimension", "prosolwpclient"));
+					}
 				}
 			}

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School