ElementInvader Addons for Elementor <= 1.4.3 - Unauthenticated Stored Cross-Site Scripting
Description
The ElementInvader Addons for Elementor plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 1.4.3 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers 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:N/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=1.4.3What Changed in the Fix
Changes introduced in v1.4.4
Source Code
WordPress.org SVNThis research plan focuses on exploiting a Stored Cross-Site Scripting (XSS) vulnerability in the **ElementInvader Addons for Elementor** plugin. ### 1. Vulnerability Summary The **ElementInvader Addons for Elementor** plugin (up to version 1.4.3) fails to sanitize and escape user-provided input in…
Show full research plan
This research plan focuses on exploiting a Stored Cross-Site Scripting (XSS) vulnerability in the ElementInvader Addons for Elementor plugin.
1. Vulnerability Summary
The ElementInvader Addons for Elementor plugin (up to version 1.4.3) fails to sanitize and escape user-provided input in its form submission features (Contact Form and Newsletter). Specifically, unauthenticated users can submit data containing malicious JavaScript through the plugin's AJAX handlers. This data is stored in the WordPress database and subsequently executed in the browser of an administrative user when they view the submissions or "maillist" in the WordPress backend.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - AJAX Action:
elementinvader_addons_for_elementor_forms_send_form(identified fromassets/js/main.js) - Vulnerable Parameters: Any form field serialized and sent to the handler, typically
name,email,message, or custom field inputs. - Authentication: None (Unauthenticated). The handler is registered via
wp_ajax_nopriv_. - Preconditions:
- The "Simple Contact Form" or "Simple Newsletter" widget must be present on a public-facing page or post.
- An administrator must eventually view the stored submissions in the WordPress dashboard.
3. Code Flow
- Entry Point: The plugin registers an AJAX handler for unauthenticated users in PHP (inferred):
add_action('wp_ajax_nopriv_elementinvader_addons_for_elementor_forms_send_form', '...'); - Frontend Capture: In
assets/js/main.js, the plugin attaches a submit listener to forms with the class.elementinvader_addons_for_elementor_f. - Data Transmission: The JS gathers all form inputs via
this_form.serializeArray(), appends the actionelementinvader_addons_for_elementor_forms_send_form, and sends a POST request to the URL stored in the.configelement'sdata-urlattribute (usuallyadmin-ajax.php). - Backend Processing (Sink): The PHP handler receives the raw POST data and saves it to the database (likely a custom table or as a
post_type) without usingsanitize_text_field()orwp_kses(). - Rendering (Execution): When an admin accesses the "Submissions" or "Newsletter" list in the WP-Admin, the plugin fetches the raw data and echoes it directly into the HTML table/view without using
esc_html()oresc_attr().
4. Nonce Acquisition Strategy
According to the README.txt (version 1.4.0), the plugin added "Form Poc Protect with Token". This suggests a nonce or token is required for the AJAX request.
- Identify Widget Location: Scan the site for a page containing the class
elementinvader_contact_formorelementinvader_newsletter. - Navigate to Page: Use the
browser_navigatetool to open the page. - Extract Token: The token is likely a hidden input field within the form, as
main.jsusesserializeArray(). Usebrowser_evalto extract it:// Look for common nonce/token field names used by this plugin browser_eval(` document.querySelector('form.elementinvader_addons_for_elementor_f input[name="_wpnonce"]')?.value || document.querySelector('form.elementinvader_addons_for_elementor_f input[name="nonce"]')?.value || document.querySelector('form.elementinvader_addons_for_elementor_f input[name="token"]')?.value `) - AJAX URL: Extract the AJAX URL from the widget's config:
browser_eval(`document.querySelector('.elementinvader_addons_for_elementor_f .config').getAttribute('data-url')`)
5. Exploitation Strategy
Step 1: Discover/Create Target Page
If no form exists, create a page with the contact form widget.
- Command:
wp post create --post_type=page --post_title="Contact" --post_status=publish --post_content='[elementinvader_contact_form]'(Note:[elementinvader_contact_form]is an inferred shortcode based on the widget name; if it fails, manually place the widget via Elementor).
Step 2: Obtain Nonce
Navigate to the page and extract the nonce using the strategy in Section 4.
Step 3: Submit Malicious Payload
Send the exploit payload via http_request.
- Method: POST
- URL:
http://<target>/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body Parameters:
action:elementinvader_addons_for_elementor_forms_send_form_wpnonce:[EXTRACTED_NONCE]name:Attackeremail:test@example.commessage:<script>alert(document.domain)</script><img src=x onerror=alert(1)>element_id:1(usually required by Elementor widgets)
Step 4: Trigger Execution
Log in as an Administrator and navigate to the plugin's submission management page (typically found under a menu item like "ElementInvader" or "Forms").
6. Test Data Setup
- Environment: WordPress with Elementor and ElementInvader Addons (<= 1.4.3) active.
- Widget Placement: Ensure at least one "Simple Contact Form" is active on a public page.
- User: An unauthenticated visitor session.
7. Expected Results
- The AJAX request should return a JSON response with
{"success": true}. - Upon visiting the backend submission list, a browser alert should trigger showing the site's domain, confirming the script executed in the admin's session.
8. Verification Steps (Post-Exploit)
Confirm the payload is stored in the database:
- Command:
wp db query "SELECT * FROM wp_posts WHERE post_content LIKE '%<script>alert%';"(Or check the specific table if identified, e.g.,wp_eli_forms). - Command:
wp option get elementinvader_addons_for_elementor_settings(Check if any global logs/settings contain the payload).
9. Alternative Approaches
- Newsletter Vector: If the Contact Form fails, target the Newsletter widget. The action name is likely
elementinvader_addons_for_elementor_newsletter_send_form. - Search Form Vector: Target the "Blog Search" widget. If the plugin logs search queries for the admin to see "Top Searches," inject the payload into the search query parameter.
- Bypass Nonce: If the nonce is strictly checked, verify if the
wp_ajax_nopriv_handler usescheck_ajax_refererwith thedieargument set tofalse, or if it fails to check the return value ofwp_verify_nonce. If it does, the request can be sent without a valid nonce.
Summary
The ElementInvader Addons for Elementor plugin is vulnerable to unauthenticated stored Cross-Site Scripting (XSS) due to insufficient input sanitization and output escaping in its form processing. Attackers can inject malicious scripts into contact or newsletter form submissions, which are then stored and executed in the browser of an administrator when viewing the submission logs in the WordPress dashboard.
Vulnerable Code
// assets/js/main.js lines 5-18 $('.elementinvader_addons_for_elementor_f').on('submit', function(e){ e.preventDefault(); var this_form = $(this); var $config = this_form.find('.config'); var conf_link = $config.attr('data-url') || 0; var load_indicator = this_form.find('.ajax-indicator-masking'); var box_alert = this_form.find('.elementinvader_addons_for_elementor_f_box_alert').html(''); load_indicator.css('display', 'inline-block'); var data = this_form.serializeArray(); if(typeof data['action'] == 'undefined') data.push({ name: 'action', value: "elementinvader_addons_for_elementor_forms_send_form" }); $.post(conf_link, data,
Security Fix
@@ -1,5 +1,7 @@ /* alerts css */ +/* Support both .eli_alert and .elementinvader_addons_for_elementor_alert (and all alert types) */ +.eli_alert, .elementinvader_addons_for_elementor_alert { position: relative; padding: .75rem 1.25rem; @@ -8,41 +10,49 @@ border-radius: .25rem; } +.eli_alert-primary, .elementinvader_addons_for_elementor_alert-primary { color: #004085; background-color: #cce5ff; border-color: #b8daff; }
Exploit Outline
An unauthenticated attacker identifies a public page containing the plugin's 'Simple Contact Form' or 'Simple Newsletter' widget. They extract the AJAX URL (typically wp-admin/admin-ajax.php) and any necessary security tokens/nonces from the hidden input fields within the form. The attacker then sends a POST request to this endpoint with the action set to 'elementinvader_addons_for_elementor_forms_send_form', including a JavaScript payload in one of the form parameters (such as 'message' or 'name'). The payload is stored in the database and executes whenever an administrator views the submissions or maillist in the WordPress backend management area.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.