Envo's Templates & Widgets for Elementor and WooCommerce <= 1.4.26 - Missing Authorization to Authenticated (Author+) Private Content Disclosure via Envo Tabs Widget 'templates' Setting
Description
The Envo's Templates & Widgets for Elementor and WooCommerce plugin for WordPress is vulnerable to unauthorized access of data due to a missing authorization check on the Envo Tabs (and Off Canvas) widget's template rendering in versions up to, and including, 1.4.26. The render() method of the Tabs widget passes a user-controlled template/post ID directly to Elementor's get_builder_content_for_display() without verifying the referenced post's status (published/private/draft) or the visitor's authorization to view it. This makes it possible for authenticated attackers, with Author-level access and above, to disclose the contents of private Elementor-driven pages and templates to anonymous visitors by configuring an Envo Tabs widget on a public post to reference the private content's ID (which can be supplied by editing the underlying Elementor widget JSON via the Elementor editor REST API).
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:NTechnical Details
<=1.4.26What Changed in the Fix
Changes introduced in v1.4.27
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-11600 ## 1. Vulnerability Summary The **Envo's Templates & Widgets for Elementor and WooCommerce** plugin (<= 1.4.26) is vulnerable to **Missing Authorization** in the `Envo Tabs` and `Off Canvas` widgets. The widget's `render()` method takes a post/template I…
Show full research plan
Exploitation Research Plan: CVE-2026-11600
1. Vulnerability Summary
The Envo's Templates & Widgets for Elementor and WooCommerce plugin (<= 1.4.26) is vulnerable to Missing Authorization in the Envo Tabs and Off Canvas widgets. The widget's render() method takes a post/template ID from the widget's settings (configured in the Elementor editor) and passes it directly to Elementor's get_builder_content_for_display() function.
Crucially, the plugin fails to verify if the post ID being rendered is "Published" or if the current visitor has permission to view it. This allows an authenticated user with "Author" privileges (who can use Elementor to edit their own posts) to inject the ID of a "Private" or "Draft" post/template belonging to another user (e.g., an Administrator). When the Author's post is viewed by an anonymous visitor, the plugin renders the sensitive content of the private post.
2. Attack Vector Analysis
- Entry Point: The
render()method of theETWWElementor\Modules\Tabs\Widgets\Tabsclass (and similarly the Off Canvas widget). - Vulnerable Parameter: The
templatessetting within the Elementor widget JSON data. - Authentication: Requires Author-level access (or any role capable of using the Elementor Editor).
- Payload: A JSON object representing an Elementor widget configuration where the
templatessetting is set to the ID of a private post/template. - Preconditions:
- A private post or Elementor template containing sensitive data must exist (target ID).
- The attacker must have permissions to create/edit a post with Elementor.
3. Code Flow
Configuration Phase (Authenticated Author):
- The Author edits a post using Elementor.
- The Author adds an
etww-tabswidget. - The Author saves the post. The configuration is stored in the
_elementor_datapost meta. - Using the WordPress REST API or Elementor Editor API, the Author modifies the
templatesvalue in the JSON payload to point to a private post ID (e.g., ID1337).
Rendering Phase (Anonymous Visitor):
- A visitor requests the URL of the Author's post.
- WordPress initializes Elementor, which calls
ETWWElementor\Modules\Tabs\Widgets\Tabs::render(). render()retrieves settings via$this->get_settings_for_display().- The code (inferred from patch) executes:
echo Plugin::$instance->frontend->get_builder_content_for_display( $settings['templates'] ); get_builder_content_for_display()fetches the post by ID and renders its content regardless of status (Private/Draft) because the authorization check is missing in the caller (Tabswidget).
4. Nonce Acquisition Strategy
The exploit involves two stages: one authenticated (to set up the payload) and one unauthenticated (to trigger the disclosure).
Authenticated Stage (Author)
To save the malicious widget configuration, the Author needs a REST API nonce.
- Navigate to the Post Editor: Access the Elementor editor for a post the Author owns.
- Extract Nonce: The nonce for the WordPress REST API is typically localized as
wpApiSettings.nonce. - JS Execution:
browser_eval("wpApiSettings.nonce")
5. Exploitation Strategy
Step 1: Discover Target ID
The attacker needs the ID of the private post. In a real-world scenario, this might be brute-forced or found via other info leaks. For this PoC, we will assume the ID is known after setup.
Step 2: Inject Malicious Widget (Authenticated)
As the Author, send a request to update the post's Elementor data.
- Endpoint:
POST /wp-json/wp/v2/posts/{POST_ID}(Standard WP REST API) orPOST /wp-json/elementor/v1/editor-data - Method:
POST - Headers:
X-WP-Nonce: [NONCE]Content-Type: application/json
- Payload:
The_elementor_datameta field must contain a JSON string. The crucial part is theetww-tabswidget:[ { "id": "random_id", "elType": "widget", "widgetType": "etww-tabs", "settings": { "tabs": [ { "tab_title": "Exploit Tab", "source": "template", "templates": "TARGET_PRIVATE_POST_ID" } ] } } ]
Step 3: Disclosure (Unauthenticated)
- Endpoint:
GET /?p={AUTHOR_POST_ID} - Action: Access the post as an anonymous user.
- Result: The content of the private post (TARGET_PRIVATE_POST_ID) will be rendered within the Tab content.
6. Test Data Setup
- Administrator User:
- Create a private post (ID
X) with the content:"SECRET_DATA_INTERNAL_ONLY". - Ensure the post status is
private.
- Create a private post (ID
- Author User:
- Create a user with the
Authorrole. - Create a public post (ID
Y) and enable Elementor for it.
- Create a user with the
- Plugin Config:
- Ensure "Envo's Templates & Widgets" is active.
7. Expected Results
- When accessing
GET /?p=Y(the Author's post) as an anonymous user, the string"SECRET_DATA_INTERNAL_ONLY"should be visible in the HTML response inside theetww-tabscontainer. - Normally, this content would be inaccessible to anonymous users and Authors.
8. Verification Steps
- Check Status: Use
wp post get X --field=post_statusto confirm the target post is indeedprivate. - Check Response: Search the HTML of the Author's post for the secret string:
http_request("GET", "http://localhost:8080/?p=Y")-> Verify presence of"SECRET_DATA_INTERNAL_ONLY".
9. Alternative Approaches
If updating via REST API is blocked, the attacker can use admin-ajax.php with the action elementor_ajax to save editor data:
- Action:
elementor_ajax - Data:
actions={"save_builder":{"action":"save_builder","data":{"status":"publish","elements":[...]}}} - Nonce: Required from
window.elementorConfig.api_nonce.
If the Tabs widget is not available, try the etww-off-canvas widget, as the description indicates it is also vulnerable. The setting name might be template_id or templates (check register_controls in modules/off-canvas/widgets/off-canvas.php if available).
Summary
The Envo Tabs widget in Envo's Templates & Widgets for Elementor and WooCommerce fails to verify the status or permissions of templates it renders via post IDs. This allows authenticated users with Author-level access to inject private post IDs into the widget settings, resulting in the disclosure of sensitive private content to anonymous visitors.
Vulnerable Code
// modules/tabs/widgets/tabs.php line 1267 } else if ('template' == $item['source'] && ('0' != $item['templates'] && !empty($item['templates']))) { echo Plugin::instance()->frontend->get_builder_content_for_display($item['templates']); }
Security Fix
@@ -1265,7 +1265,9 @@ if ('custom' == $item['source'] && !empty($item['tab_content'])) { echo $this->parse_text_editor($item['tab_content']); } else if ('template' == $item['source'] && ('0' != $item['templates'] && !empty($item['templates']))) { - echo Plugin::instance()->frontend->get_builder_content_for_display($item['templates']); + if (get_post_status($item['templates']) === 'publish') { + echo Plugin::instance()->frontend->get_builder_content_for_display($item['templates']); + } } ?> </div>
Exploit Outline
The exploit is executed by an authenticated attacker with Author-level privileges or higher. 1. The attacker identifies the ID of a private post or Elementor template containing sensitive data. 2. The attacker creates or edits a post they own using the Elementor editor and adds the 'Envo Tabs' (etww-tabs) widget. 3. Using the WordPress REST API (targeting the post's meta) or the Elementor Editor AJAX API (action: 'elementor_ajax'), the attacker manually updates the widget configuration JSON in the '_elementor_data' field. They set the 'source' to 'template' and the 'templates' parameter to the ID of the target private post. 4. Once the post is saved, the attacker or any anonymous visitor navigates to the public URL of the Author's post. 5. The 'render()' method in the Tabs widget fetches the private post content via 'get_builder_content_for_display()' and displays it on the page because it lacks a check for 'publish' status or user authorization.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.