Exclusive Addons for Elementor <= 2.7.9.9 - Unauthenticated Information Exposure
Description
The Exclusive Addons for Elementor plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 2.7.9.9. This makes it possible for unauthenticated attackers to extract sensitive user or configuration data.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:NTechnical Details
<=2.7.9.9What Changed in the Fix
Changes introduced in v2.8.0
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-59511 ## 1. Vulnerability Summary The **Exclusive Addons for Elementor** plugin (versions <= 2.7.9.9) is vulnerable to **Unauthenticated Information Exposure**. The vulnerability stems from the plugin's failure to filter sensitive configuration data when pass…
Show full research plan
Exploitation Research Plan - CVE-2026-59511
1. Vulnerability Summary
The Exclusive Addons for Elementor plugin (versions <= 2.7.9.9) is vulnerable to Unauthenticated Information Exposure. The vulnerability stems from the plugin's failure to filter sensitive configuration data when passing widget settings to the frontend for features like AJAX pagination and "Load More" functionality. Specifically, widgets like the Facebook Feed include sensitive API credentials (e.g., exad_facebook_access_token) in the settings object, which is then exposed to unauthenticated visitors via localized JavaScript variables or AJAX responses.
2. Attack Vector Analysis
- Endpoint:
admin-ajax.php(for AJAX-based exposure) or any public page containing the affected widget (for source-based exposure). - Vulnerable Action:
exad_ajax_paginationandexad_facebook_feed_action. - Authentication: None (Unauthenticated).
- Preconditions: A "Facebook Feed" widget must be configured on a published page with an Access Token.
- Severity: Medium (CVSS 5.3) - Allows extraction of sensitive API tokens, which can be used to impersonate the site owner on third-party platforms (Facebook).
3. Code Flow
- Registration: In
base.php, the plugin registers unauthenticated AJAX handlers:add_action( 'wp_ajax_nopriv_ajax_pagination', [ __CLASS__, 'exad_ajax_pagination' ] ); add_action( 'wp_ajax_nopriv_exad_facebook_feed_action', [ $this, 'exad_facebook_feed_ajax' ] ); - Control Definition: In
elements/facebook-feed/facebook-feed.php, the widget defines sensitive controls:$this->add_control( 'exad_facebook_access_token', [ 'label' => esc_html__('Access Token', 'exclusive-addons-elementor' ), 'type' => Controls_Manager::TEXT, 'default' => 'EAAkn4TitXB...', // Default token provided // ... ] ); - Exposure (Frontend): When the widget renders, it enqueues scripts. The plugin's core logic (likely in the
enqueue_scriptsmethod ofBase) useswp_localize_scriptto pass the entire$settingsarray of the widget to the frontend to facilitate AJAX "Load More" actions. - Exposure (AJAX): The
exad_ajax_paginationfunction (inbase.php) may return the settings object or require it to be sent back and forth. If the server retrieves and returns these settings without strippingexad_facebook_access_token, the information is exposed.
4. Nonce Acquisition Strategy
The AJAX actions require a nonce for verification. This nonce is exposed in the frontend HTML.
- Identify Trigger: The
exad-facebook-feedwidget orPost Gridwidget triggers the script loading. - Create Test Page:
wp post create --post_type=page --post_title="Exploit Test" --post_status=publish --post_content='[exad-facebook-feed]' - Navigate and Extract: Use
browser_navigateto the new page. - Extract via JS: Use
browser_evalto find the localized data. Based on the plugin structure, the variable is likelyexad_ajax_query_config(inferred) or part of theexclusive-addons-elementorlocalization.- Check:
browser_eval("window.exad_ajax_query_config") - Check:
browser_eval("window.exad_facebook_feed_settings")(inferred) - The nonce key is typically
nonceorajax_nonce.
- Check:
5. Exploitation Strategy
The goal is to retrieve the exad_facebook_access_token from an unauthenticated context.
Method A: Direct Page Source Extraction (Most Likely)
- Step 1: Use
http_request(GET) to fetch the URL of a page containing a Facebook Feed. - Step 2: Search the response body for the configuration object.
- Target string:
"exad_facebook_access_token":"
- Target string:
- Expected Payload Location: Inside a
<script>tag with the IDexclusive-addons-elementor-js-extraor similar.
Method B: AJAX Response Extraction
- Step 1: Obtain a valid nonce and the
post_idfrom the target page. - Step 2: Craft a POST request to
admin-ajax.php.POST /wp-admin/admin-ajax.php HTTP/1.1 Content-Type: application/x-www-form-urlencoded action=exad_ajax_pagination&id=[POST_ID]&nonce=[NONCE]&widget_id=[WIDGET_ID] - Step 3: Analyze the JSON response for the presence of the
settingsblock containing the access token.
6. Test Data Setup
- Install Plugin: Ensure
exclusive-addons-for-elementorversion2.7.9.9is active. - Configure Widget:
- Use
wp post createto create a page. - Manually or via CLI, update the
_elementor_datapost meta to include aFacebook Feedwidget with a unique, identifiable string as theexad_facebook_access_token. - Example identifying string:
SENSITIVE_TOKEN_1234567890
- Use
7. Expected Results
- A successful exploit will return the string
SENSITIVE_TOKEN_1234567890in an unauthenticated HTTP response. - This proves that an unauthorized actor can extract private API credentials configured by the site administrator.
8. Verification Steps
- Check Database:
wp post meta get <POST_ID> _elementor_data - Compare: Verify the string found in the HTTP response matches the token stored in the database.
- Validate Unauthenticated: Ensure the
http_requestwas sent without any session cookies.
9. Alternative Approaches
If the Facebook token is not exposed, check other widgets that use external APIs, such as:
- Instagram Feed
- Mailchimp
- Google Maps
The search pattern for any sensitive exposure in the JS localization is:
grep -r "wp_localize_script" . -A 5 | grep "settings"
This will identify where the plugin is passing widget settings to the frontend. Look for any call that passes an unfiltered $settings array.
Summary
The Exclusive Addons for Elementor plugin exposes sensitive API credentials, such as Facebook Access Tokens, by including them in widget settings passed to the frontend for AJAX pagination features. Unauthenticated attackers can retrieve these tokens from the page source where they are embedded in data attributes or localized JavaScript, enabling them to impersonate the site owner on third-party platforms.
Vulnerable Code
// elements/facebook-feed/facebook-feed.php $query_settings = [ 'widget_id' => $id, 'page_id' => $page_id, 'access_token' => $access_token, 'clear_cache' => $settings['clear_cache'], 'exad_facebook_sort_by' => $settings['exad_facebook_sort_by'], 'post_limit' => $settings['post_limit'], --- // base.php public function exad_facebook_feed_ajax() { $security = check_ajax_referer('exclusive_addons_nonce', 'security'); if ( true == $security && isset( $_POST['query_settings'] ) ) : $settings = $_POST['query_settings']; $loaded_item = $_POST['loaded_item'];
Security Fix
@@ -10,6 +10,7 @@ use Elementor\Plugin; use ExclusiveAddons\Elementor\Exad_WPML_Element_Free_Compatibility; +use \Elementor\Utils; if ( ! defined( 'ABSPATH' ) ) { exit; @@ -340,6 +341,11 @@ return $element; } + protected function is_widget_id_valid( $widget_id ) { + return preg_match( '/^[a-zA-Z0-9]+$/', $widget_id ) + && strlen( $widget_id ) === 7; + } + /** * Facebook Feed ajax call @@ -351,16 +357,56 @@ $security = check_ajax_referer('exclusive_addons_nonce', 'security'); if ( true == $security && isset( $_POST['query_settings'] ) ) : - $settings = $_POST['query_settings']; - $loaded_item = $_POST['loaded_item']; - + $error_message = esc_html__( 'Something went wrong, please refresh the page.', 'exclusive-addons-elementor' ); + + if ( ! is_array( $_POST[ 'query_settings' ] ) ) { + + return $error_message; + } + + $settings = wp_kses_post_deep( wp_unslash( $_POST[ 'query_settings' ] ) ); + $loaded_item = wp_kses_post( wp_unslash( $_POST[ 'loaded_item' ] ) ); + + $post_id = absint( $settings['post_id'] ); + $widget_id = esc_attr( $settings['widget_id'] ); + + if ( ! $post_id || ! $this->is_widget_id_valid( $widget_id ) ) { + + return $error_message; + } + + Plugin::$instance->db->switch_to_post( $post_id ); + $document = Plugin::$instance->documents->get( $post_id ); + + // Bail if not Elementor page. + if ( ! $document ) { + + return $error_message; + } + + // Setup $post_id as the WP global $post + $post = get_post( $post_id, OBJECT ); + setup_postdata( $post ); + + $elements_data = $document->get_elements_data(); + $widget_data = Utils::find_element_recursive( $elements_data, $widget_id ); + $widget_instance = Plugin::$instance->elements_manager->create_element_instance( $widget_data ); + $widget_settings = $widget_instance->get_settings_for_display(); + + if ( ! isset( $widget_settings['exad_facebook_access_token'] ) ) { + + return $error_message; + } + + $settings['access_token'] = $widget_settings['exad_facebook_access_token']; + $exad_facebook_feed_cache = '_' . $settings['widget_id'] . '_facebook_cache'; $transient_key = $settings['exad_facebook_page_id'] . $exad_facebook_feed_cache; $facebook_feed_data = get_transient($transient_key); if ( false === $facebook_feed_data ) { $url_queries = 'fields=status_type,created_time,from,message,story,full_picture,permalink_url,attachments.limit(1){type,media_type,title,description,unshimmed_url},comments.summary(total_count),reactions.summary(total_count)'; - $url = "https://graph.facebook.com/{$settings['page_id']}/posts?{$url_queries}&access_token={$settings['access_token']}"; + $url = "https://graph.facebook.com/{$settings['exad_facebook_page_id']}/posts?{$url_queries}&access_token={$settings['access_token']}"; $data = wp_remote_get( $url ); $facebook_feed_data = json_decode( wp_remote_retrieve_body( $data ), true ); set_transient( $transient_key, $facebook_feed_data, 0 ); @@ -368,6 +414,17 @@ if ( $settings['clear_cache'] == 'yes' ) { delete_transient( $transient_key ); } + + if ( !empty( $facebook_feed_data ) && array_key_exists( 'error', $facebook_feed_data ) ) { + $messages['error'] = $facebook_feed_data['error']['message']; + } + + if ( !empty( $messages ) ) { + foreach ($messages as $key => $message) { + printf('<div class="exad-facebook-error-message">%1$s</div>', esc_html( $message ) ); + } + return; + } switch ($settings['exad_facebook_sort_by']) { case 'old-posts': @@ -1489,6 +1490,8 @@ if ( empty( $page_id ) || empty( $access_token ) ) { return; } + + $current_post_id = get_the_ID(); $this->add_render_attribute( 'exad_facebook_feed_wrapper', @@ -1529,9 +1532,9 @@ $query_settings = [ + 'post_id' => $current_post_id, 'widget_id' => $id, - 'page_id' => $page_id, - 'access_token' => $access_token, + 'exad_facebook_page_id' => $page_id, 'clear_cache' => $settings['clear_cache'], 'exad_facebook_sort_by' => $settings['exad_facebook_sort_by'], 'post_limit' => $settings['post_limit'],
Exploit Outline
The exploit involves retrieving sensitive API credentials from the frontend of a WordPress site using the Exclusive Addons for Elementor plugin. 1. **Identify Target Page:** Locate a public page that utilizes the 'Facebook Feed' widget. 2. **Inspect Page Source:** Analyze the HTML source code of the identified page. The plugin embeds widget configuration data inside the `data-settings` attribute of the widget's wrapper element (e.g., `.exad-facebook-feed-wrapper`). 3. **Extract Credentials:** Locate the `exad_facebook_access_token` or `access_token` key within the JSON-encoded `data-settings` attribute value. This token can also often be found within localized JavaScript variables passed via `wp_localize_script` (e.g., in a script tag with the ID `exclusive-addons-elementor-js-extra`). 4. **Verification:** Use the extracted Access Token to make authenticated requests to the Facebook Graph API, confirming the exposure and severity. No authentication is required for the attacker to perform the extraction.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.