The Plus Addons for Elementor – Addons for Elementor, Page Templates, Widgets, Mega Menu, WooCommerce <= 6.4.11 - Authenticated (Contributor+) Stored Cross-Site Scripting
Description
The The Plus Addons for Elementor – Addons for Elementor, Page Templates, Widgets, Mega Menu, WooCommerce plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 6.4.11 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.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=6.4.11Source Code
WordPress.org SVNThis research plan outlines the technical requirements and steps to demonstrate a Stored Cross-Site Scripting (XSS) vulnerability in "The Plus Addons for Elementor" (versions <= 6.4.11). This vulnerability allows Contributor-level users to inject malicious scripts into pages, which then execute in t…
Show full research plan
This research plan outlines the technical requirements and steps to demonstrate a Stored Cross-Site Scripting (XSS) vulnerability in "The Plus Addons for Elementor" (versions <= 6.4.11). This vulnerability allows Contributor-level users to inject malicious scripts into pages, which then execute in the context of any user (including Administrators) viewing those pages.
1. Vulnerability Summary
- Vulnerability Name: The Plus Addons for Elementor Stored XSS
- Vulnerability Type: Improper Neutralization of Input During Web Page Generation (Stored XSS)
- Vulnerability Component: Various widgets and the "Plus Extra Attributes" feature.
- Root Cause: The plugin fails to sanitize user-provided input in widget settings (such as IDs, classes, or custom data attributes) and subsequently fails to escape this data when rendering the widget on the frontend using functions like
echoinstead ofesc_attr(). - Affected Versions: <= 6.4.11
2. Attack Vector Analysis
- Endpoint: WordPress REST API (Elementor Editor endpoint) or the standard Post Save mechanism.
- Action/Hook:
wp_ajax_elementor_ajaxor REST routes handled by Elementor'sEditorclass. - Vulnerable Parameter:
post_content(within the JSON-encodedsettingsof a specific "Plus" widget or extra attribute). - Authentication: Contributor-level access (or higher) is required to edit posts and access the Elementor editor.
- Preconditions: The "The Plus Addons for Elementor" plugin must be active, and the Contributor must have permission to edit the specific post/page.
3. Code Flow (Inferred)
- Input: A Contributor user opens the Elementor editor for a post and adds a widget from "The Plus Addons" (e.g., Heading, Button, or any widget with Plus Extra Attributes enabled).
- Storage: The user enters a payload (e.g.,
"><script>alert(1)</script>) into a setting field like "Custom ID" or a "Custom Attribute". Elementor sends this data via a REST API request to save the post metadata. - Processing: The plugin saves these settings into the
_elementor_datapost meta without sanitization. - Output (Sink): When a user views the post, Elementor triggers the
render()method of the widget class. - Vulnerability: Inside the
render()method (likely inincludes/widgets/or via a filter inmodules/), the plugin retrieves the custom attribute and outputs it directly into the HTML:// Example of vulnerable code pattern $id = $settings['plus_extra_id']; echo '<div id="' . $id . '">'; // No esc_attr() here
4. Nonce Acquisition Strategy
Elementor exploitation requires the wp_rest nonce for authenticated REST API calls.
- Identify the Trigger: Elementor's editor needs to be active.
- Create Test Content: Create a page and set it to be edited with Elementor.
wp post create --post_type=page --post_status=publish --post_title="XSS Research" --post_content=''
- Extract Nonce:
- Navigate to the WordPress dashboard and find the "Edit with Elementor" link for the newly created page.
- Navigate to that editor URL using
browser_navigate. - Use
browser_evalto extract the REST nonce from the Elementor configuration object:// Elementor stores the REST nonce in the following location window.elementorCommonConfig?.api_nonce; - If a plugin-specific AJAX nonce is required (for non-Elementor actions), look for:
window.theplus_ajax_nonce; // Inferred from common plugin JS localization
5. Exploitation Strategy
The goal is to inject a script into a widget setting that is rendered as an HTML attribute.
Step-by-Step Plan:
- Authentication: Log in as a Contributor user.
- Capture Editor Context: Access the Elementor editor for a page to get the
post_idand thewp_restnonce. - Craft Payload: The payload should break out of an HTML attribute.
- Target Field:
Custom IDorPlus Extra Attributes->Attribute Value. - Payload:
x" onmouseover="alert(document.domain)" data-x="
- Target Field:
- Send Update Request: Use
http_requestto send aPOSTrequest to the Elementor REST API endpoint to update the post content.- URL:
https://TARGET/wp-json/elementor/v1/data/<POST_ID> - Method:
POST - Headers:
Content-Type: application/jsonX-WP-Nonce: <EXTRACTED_NONCE>
- Body: A JSON structure representing the Elementor widget tree, including the malicious payload in the widget's settings.
- URL:
6. Test Data Setup
- Plugin Version: Ensure "The Plus Addons for Elementor" v6.4.11 is installed.
- User: Create a user with the
contributorrole. - Page: Create a page with the title "Research Page" and identify its ID.
- Enable Features: Ensure "Plus Extra Attributes" is enabled in the plugin's settings (if testing that specific vector).
7. Expected Results
- Response: The REST API should return a
200 OKindicating the post was saved. - Rendering: When visiting the page at
https://TARGET/?p=<POST_ID>, the HTML source should contain the injected payload:<div id="x" onmouseover="alert(document.domain)" data-x="" ...> - Execution: Triggering the
onmouseoverevent (or using a<script>tag if the field is echoed outside an attribute) will execute the JavaScript.
8. Verification Steps
- WP-CLI Verification: Check the post metadata to see the stored payload:
wp post meta get <POST_ID> _elementor_data
- Database Check: Inspect the
wp_postmetatable directly if needed:wp db query "SELECT meta_value FROM wp_postmeta WHERE post_id=<POST_ID> AND meta_key='_elementor_data'"
- Frontend Inspection: Use
http_request(GET) on the public page URL and grep for the payload string.
9. Alternative Approaches
- Shortcode Vector: If the Elementor Editor is restricted, attempt to use the plugin's shortcodes in a standard post. If a shortcode attribute like
idorclassis vulnerable:- Payload:
[tp_button id='"><script>alert(1)</script>']
- Payload:
- Other Widgets: The "Plus Addons" package contains many widgets. If the "Heading" widget is patched, test the "Accordion", "Tabs", or "Info Box" widgets, as the same vulnerable code pattern often replicates across similar components in the same plugin.
Summary
The Plus Addons for Elementor plugin is vulnerable to Stored Cross-Site Scripting via various widget settings and the 'Plus Extra Attributes' feature. Authenticated users with Contributor-level access can inject malicious JavaScript into fields like custom IDs or attributes, which then executes in the context of any user viewing the affected page.
Vulnerable Code
// File: includes/widgets/some-plus-widget.php (approximate) // The plugin fails to escape user-provided settings before outputting them in HTML attributes. public function render() { $settings = $this->get_settings_for_display(); $custom_id = $settings['plus_extra_id']; // Vulnerable: Outputting raw setting value into the 'id' attribute echo '<div id="' . $custom_id . '" class="tp-widget-container">'; } --- // File: modules/enqueue/plus-extra-attributes.php (approximate) // Custom attributes added via the Plus Extra Attributes feature are often concatenated directly. foreach ( $extra_attributes as $attribute ) { $attr_key = $attribute['attr_key']; $attr_val = $attribute['attr_val']; // Vulnerable: Direct echo of key/value without sanitization or escaping echo ' ' . $attr_key . '="' . $attr_val . '"'; }
Security Fix
@@ -10,7 +10,7 @@ $settings = $this->get_settings_for_display(); $custom_id = $settings['plus_extra_id']; - echo '<div id="' . $custom_id . '" class="tp-widget-container">'; + echo '<div id="' . esc_attr($custom_id) . '" class="tp-widget-container">'; @@ -15,5 +15,5 @@ $attr_key = $attribute['attr_key']; $attr_val = $attribute['attr_val']; - echo ' ' . $attr_key . '="' . $attr_val . '"'; + echo ' ' . esc_attr($attr_key) . '="' . esc_attr($attr_val) . '"';
Exploit Outline
The exploit targets the Elementor Editor REST API endpoint which is accessible to Contributor-level users. 1. **Authentication**: Log in as a Contributor and access the Elementor editor for a post to obtain the `wp_rest` nonce from the `window.elementorCommonConfig.api_nonce` object. 2. **Payload Construction**: Create a JSON payload representing an Elementor widget (e.g., Heading or Button) from 'The Plus Addons'. In the widget's `settings`, inject a malicious payload into a field that generates HTML attributes, such as `plus_extra_id` or `plus_extra_attributes`. 3. **Payload Example**: `"plus_extra_id": "x\" onmouseover=\"alert(document.domain)\" data-x=\""`. 4. **Persistence**: Send a `POST` request to `/wp-json/elementor/v1/data/<POST_ID>` with the malicious JSON and the `X-WP-Nonce` header. 5. **Execution**: When any user (including an Administrator) views the page, the injected attribute breaks out of the intended `id` attribute and adds an event handler, executing the script when the element is interacted with (e.g., hovered).
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.