Elementor Website Builder <= 3.35.7 - Incorrect Authorization to Authenticated (Contributor+) Sensitive Information Exposure via Elementor Template
Description
The Elementor Website Builder plugin for WordPress is vulnerable to Incorrect Authorization to Sensitive Information Exposure in all versions up to, and including, 3.35.7. This is due to a logic error in the is_allowed_to_read_template() function permission check that treats non-published templates as readable without verifying edit capabilities. This makes it possible for authenticated attackers, with contributor-level access and above, to read private or draft Elementor template content via the 'template_id' supplied to the 'get_template_data' action of the 'elementor_ajax' endpoint.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:NTechnical Details
What Changed in the Fix
Changes introduced in v3.35.8
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-1206 (Elementor Website Builder) ## 1. Vulnerability Summary The **Elementor Website Builder** plugin (versions <= 3.35.7) contains an authorization bypass vulnerability in its template library management logic. Specifically, the function `is_allowed_to_read_t…
Show full research plan
Exploitation Research Plan: CVE-2026-1206 (Elementor Website Builder)
1. Vulnerability Summary
The Elementor Website Builder plugin (versions <= 3.35.7) contains an authorization bypass vulnerability in its template library management logic. Specifically, the function is_allowed_to_read_template() (inferred to be within the Template_Library module) fails to properly validate a user's permission to view templates that are not in a 'published' state (e.g., Drafts, Private, or Pending Review).
While the code correctly restricts sensitive templates for unauthenticated users, it incorrectly assumes that any authenticated user with access to the Elementor AJAX endpoint (which includes Contributors) is authorized to read the content of non-published templates without checking if the specific user has the capability to edit that post. This allows a Contributor to leak the full JSON content, including potentially sensitive configurations or internal data, of any template on the site by providing its template_id.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
elementor_ajax - Sub-Action (Elementor Internal):
get_template_data - Required Parameter:
template_id(the ID of the target private/draft template) - Authentication: Authenticated, Contributor role or higher.
- Preconditions: The attacker must know or guess the ID of a private or draft template (which can be found via ID enumeration).
3. Code Flow
- Entry Point: The request hits
admin-ajax.phpwithaction=elementor_ajax. - AJAX Handler: Elementor's central AJAX handler (likely in
Core\Common\Modules\Ajax\Module->handle_ajax_request()) iterates through theactionsprovided in the POST body. - Dispatch: The internal action
get_template_datais dispatched to the Template Library manager. - Vulnerable Function: The manager calls
is_allowed_to_read_template($template_id). - Logic Error: The function checks the post status of the
$template_id. If the status is notpublish(e.g.,draft), it bypasses the strictedit_postcapability check and returnstrue, erroneously allowing the read operation. - Data Leak: The function
get_template_dataproceeds to fetch the template's content and returns it in the JSON response.
4. Nonce Acquisition Strategy
Elementor's AJAX endpoint requires a specific nonce. For a logged-in Contributor, this nonce is globally available in the WordPress admin dashboard where Elementor scripts are loaded.
- Log in as a Contributor.
- Navigate to any Elementor-related admin page (e.g.,
wp-admin/edit.php?post_type=elementor_library). - Extraction: Use
browser_evalto extract the AJAX nonce from theelementorCommonorelementorAdminconfiguration objects.- Key:
window.elementorCommon.config.ajax.nonce - Alternative Key:
window.elementorAdminConfig.ajax_nonce(inferred fromassets/js/admin.js).
- Key:
5. Exploitation Strategy
Step 1: Discover Target Template ID
The attacker can enumerate Post IDs via the REST API or by guessing IDs if a specific private template is suspected. For the PoC, we will create a private template as an Admin and note its ID.
Step 2: Extract AJAX Nonce
Navigate to the WordPress dashboard as a Contributor and run:
// Browser Eval
return window.elementorCommon.config.ajax.nonce;
Step 3: Send Malicious AJAX Request
Send a POST request to admin-ajax.php. Elementor's AJAX handler expects a specific nested JSON format for the actions parameter.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=elementor_ajax&_nonce=[EXTRACTED_NONCE]&actions={"get_template_data":{"action":"get_template_data","data":{"template_id":[TARGET_PRIVATE_ID]}}}
Step 4: Analyze Response
A successful exploit will return a 200 OK with a JSON body containing the data key for the requested template, revealing the full Elementor widget tree and content.
6. Test Data Setup
- Admin Action: Create an Elementor Template (e.g., a "Section" template).
- Title: "Sensitive Admin Data"
- Content: Add a Text Editor widget with the string
SECRET_ADMIN_TOKEN_12345. - Status: Set to Draft or Private.
- ID: Note the ID (e.g.,
15).
- Admin Action: Create a user with the Contributor role.
- Login: Authenticate as the Contributor.
7. Expected Results
- Success: The response JSON contains
"success":trueand thedatafield contains the serialized Elementor content of the private template, including the stringSECRET_ADMIN_TOKEN_12345. - Failure: The response returns a
403 Forbiddenor a JSON error stating the user is not allowed to perform the action.
8. Verification Steps
- Via Browser: Verify the Contributor cannot see the private template in the "Templates" list (
wp-admin/edit.php?post_type=elementor_library). - Via WP-CLI: Check the template status to confirm it is indeed private:
wp post get [ID] --field=post_status - Via PoC: Ensure the AJAX response includes the template content despite the restricted status.
9. Alternative Approaches
If the elementorCommon object is not available on the Contributor dashboard, try:
- Creating a post with an Elementor-related shortcode (e.g.,
[elementor-template id="1"]) to force-load Elementor assets on a frontend page, then extracting the nonce from there. - Checking the
admin-feedback.strings.jscontext which indicates some library features are accessible to lower roles via the "New Template" buttons. - If the
actionsJSON format differs, capture a legitimate AJAX request from an Admin session to observe the exact structure expected by theelementor_ajaxhandler.
Summary
The Elementor plugin contains a logic error in its template permission check function, `is_allowed_to_read_template()`. This function incorrectly grants access to non-published templates (such as drafts or private templates) without verifying if the user has the required edit permissions, allowing authenticated attackers with Contributor-level access to leak sensitive template data.
Vulnerable Code
// Inferred location: core/common/modules/ajax/module.php or includes/template-library/manager.php public function is_allowed_to_read_template( $template_id ) { $post_status = get_post_status( $template_id ); // Logic Error: The check returns true if the template is NOT published, // assuming that only published templates need strict capability checks. if ( 'publish' !== $post_status ) { return true; } return current_user_can( 'edit_post', $template_id ); }
Security Fix
@@ -124,10 +124,6 @@ public function is_allowed_to_read_template( $template_id ) { $post_status = get_post_status( $template_id ); - if ( 'publish' !== $post_status ) { - return true; - } - return current_user_can( 'edit_post', $template_id ); }
Exploit Outline
The exploit targets the Elementor AJAX endpoint and bypasses authorization checks for draft or private templates. 1. Authentication: The attacker must be authenticated as a Contributor or higher. 2. Nonce Acquisition: Extract the required AJAX nonce from the WordPress admin dashboard by accessing the `window.elementorCommon.config.ajax.nonce` JavaScript variable. 3. Target Identification: Enumerate or guess the ID of a private or draft template that contains sensitive information. 4. Request Construction: Send a POST request to `/wp-admin/admin-ajax.php` with the parameter `action=elementor_ajax`. 5. Payload Shape: The POST body must contain a JSON-encoded `actions` parameter specifically calling the `get_template_data` internal action: - `actions={"get_template_data":{"action":"get_template_data","data":{"template_id":[TARGET_ID]}}}` 6. Data Extraction: Because of the logic error in `is_allowed_to_read_template()`, the server will bypass the capability check for non-published IDs and return the full JSON content (including widget configurations and text content) of the requested template.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.