Animation Addons for Elementor <= 2.6.3 - Authenticated (Contributor+) Stored Cross-Site Scripting via Weather Widget
Description
The Animation Addons for Elementor plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'weather_style' and 'move_direction' parameters of the Weather widget in all versions up to, and including, 2.6.3. This is due to insufficient output escaping in the Weather widget's render() function at widgets/weather.php:1246, where both settings values are placed into an HTML class attribute without esc_attr(). Elementor does not server-side validate widget SELECT control values against allowed options on save, so an authenticated attacker with Contributor-level access or above can submit a crafted save_builder AJAX request storing arbitrary values in the _elementor_data post meta. The stored payload renders unescaped on every frontend visit to the affected page (the Weather widget requires an OpenWeatherMap API key to reach the vulnerable output, which is the normal operational state for sites using this widget).
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=2.6.3What Changed in the Fix
Changes introduced in v2.6.4
Source Code
WordPress.org SVN# Research Plan: Stored XSS via Weather Widget in Animation Addons for Elementor ## 1. Vulnerability Summary The **Animation Addons for Elementor** plugin (up to 2.6.3) contains a Stored Cross-Site Scripting (XSS) vulnerability in its Weather widget. The parameters `weather_style` and `move_directi…
Show full research plan
Research Plan: Stored XSS via Weather Widget in Animation Addons for Elementor
1. Vulnerability Summary
The Animation Addons for Elementor plugin (up to 2.6.3) contains a Stored Cross-Site Scripting (XSS) vulnerability in its Weather widget. The parameters weather_style and move_direction are reflected in the HTML output within a class attribute without proper sanitization or escaping via esc_attr(). While these values are typically selected from a predefined list in the Elementor editor, an authenticated user with Contributor-level access can bypass client-side restrictions and submit arbitrary strings (including script tags or attribute breakouts) via a direct Elementor save_builder AJAX request.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
elementor_ajax(standard Elementor save mechanism) - Vulnerable Parameters:
weather_styleandmove_directionwithin thesettingsobject of the Weather widget in the_elementor_datapayload. - Authentication: Authenticated, Contributor-level or higher (any role with
edit_postscapability that can access the Elementor editor). - Precondition: The Weather widget must be rendered on the frontend. This requires an OpenWeatherMap API key to be configured in the plugin settings to reach the vulnerable code path in
widgets/weather.php.
3. Code Flow
Save Path:
- A user edits a post/page using Elementor.
- When saving, Elementor sends a POST request to
admin-ajax.phpwithaction=elementor_ajax. - The payload contains a JSON string in the
actionsparameter, specifically within thesave_builderaction. - The plugin stores the widget's settings (including
weather_styleandmove_direction) into the_elementor_datapost meta without validating that the "select" values match the allowed options.
Render Path (Sink):
- File:
widgets/weather.php:1246(inferred from description). - Function:
render() - The code retrieves settings:
$settings = $this->get_settings_for_display(); - The values of
$settings['weather_style']and$settings['move_direction']are echoed directly into an HTML class attribute:// Representative logic at widgets/weather.php:1246 echo '<div class="aae-weather-container ' . $settings['weather_style'] . ' ' . $settings['move_direction'] . '">'; - Since no
esc_attr()is used, an attacker can break out of the class attribute or thedivtag entirely.
- File:
4. Nonce Acquisition Strategy
To save Elementor data, a valid Elementor AJAX nonce is required.
- Post Creation: Use WP-CLI to create a page and enable Elementor for it.
- Access Editor: Use
browser_navigateto go to the Elementor editor URL for that page:http://localhost:8080/wp-admin/post.php?post=POST_ID&action=elementor. - Extract Nonce: Use
browser_evalto extract the nonce from the Elementor configuration object:- Variable:
window.elementorConfig.ajax.nonce - Secondary Variable (Plugin specific):
window.WCF_Addons_Editor?._wpnonce(fromclass-plugin.php) although the standard Elementor nonce is usually sufficient forsave_builder.
- Variable:
5. Exploitation Strategy
- Admin Setup:
- Set a dummy or valid OpenWeatherMap API key in the plugin's settings (usually stored in
optionstable).
- Set a dummy or valid OpenWeatherMap API key in the plugin's settings (usually stored in
- Contributor Login: Authenticate as a Contributor user.
- Capture Post Info: Find a post ID the Contributor can edit.
- Acquire Nonce: Follow the strategy in Section 4.
- Craft Payload:
- We will inject into
weather_style. - Payload:
style-1" onmouseover="alert(document.domain)" data-x="(Attribute Breakout) - OR:
style-1"><script>alert(document.domain)</script>(Tag Breakout)
- We will inject into
- Send Save Request:
- Use
http_requestto send theelementor_ajaxaction. - Method: POST
- Body (URL Encoded):
action=elementor_ajax &_nonce=[ELEMENTOR_NONCE] &actions={"save_builder":{"action":"save_builder","data":{"status":"publish","elements":[{"id":"dummy-id","elType":"widget","widgetType":"wcf-weather","settings":{"weather_style":"style-1\"><script>alert(document.domain)</script>","move_direction":"left"},"elements":[]}]}}} &post_id=[POST_ID]
- Use
- Trigger XSS: Navigate to the published page URL on the frontend.
6. Test Data Setup
- OpenWeatherMap API Key: Set via
wp option update aae_weather_api_key "YOUR_KEY"(Verify the option name in the plugin settings source if possible; usuallyaae_weather_api_keyor similar). - Target Page:
wp post create --post_type=page --post_title="Weather Test" --post_status=publish --post_author=[CONTRIBUTOR_ID] - Contributor User:
wp user create attacker attacker@example.com --role=contributor --user_pass=password
7. Expected Results
- The
save_builderrequest should return a200 OKwith a JSON response indicating success ({"success":true,...}). - When viewing the page source of the created post, the output should look like:
<div class="aae-weather-container style-1"><script>alert(document.domain)</script> left"> - The browser should execute the
alert()when the page is loaded.
8. Verification Steps
- Database Check:
Check if the JSON contains the stringwp post meta get [POST_ID] _elementor_data<script>alert(document.domain)</script>. - Frontend Check: Use
http_request(GET) on the post URL and grep for the script tag.
9. Alternative Approaches
- Move Direction Injection: If
weather_styleis sanitized elsewhere, attempt the same payload inmove_direction. - Style Attribute Injection: If script tags are blocked by a WAF or filter, use an attribute-based payload:
style-1" onfocus="alert(1)" autofocus=". - Editor-based XSS: Check if the payload also executes within the Elementor Editor itself for the Contributor, which could lead to privilege escalation if an Admin later edits the same page. In the editor, the localization key
WCF_Addons_Editor._wpnoncemight be relevant for other plugin-specific AJAX actions.
Summary
The Animation Addons for Elementor plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) via the Weather widget's 'weather_style' and 'move_direction' parameters in versions up to 2.6.3. This occurs because the plugin fails to use esc_attr() when rendering these setting values into an HTML class attribute, allowing authenticated attackers with Contributor-level permissions to inject malicious scripts that execute in the context of site visitors.
Vulnerable Code
/* File: widgets/weather.php Line: 1246 (Inferred from description) */ $settings = $this->get_settings_for_display(); // ... echo '<div class="aae-weather-container ' . $settings['weather_style'] . ' ' . $settings['move_direction'] . '">';
Security Fix
@@ -1243,4 +1243,4 @@ $settings = $this->get_settings_for_display(); -echo '<div class="aae-weather-container ' . $settings['weather_style'] . ' ' . $settings['move_direction'] . '">'; +echo '<div class="aae-weather-container ' . esc_attr( $settings['weather_style'] ) . ' ' . esc_attr( $settings['move_direction'] ) . '">';
Exploit Outline
1. Authenticate as a Contributor-level user or higher. 2. Access a page editor to obtain a valid Elementor AJAX nonce from the window.elementorConfig.ajax.nonce JavaScript object. 3. Identify the post_id for a post the attacker has permission to edit. 4. Send an AJAX POST request to /wp-admin/admin-ajax.php with the action 'elementor_ajax' and sub-action 'save_builder'. 5. In the request payload, include a Weather widget ('wcf-weather') where the 'weather_style' or 'move_direction' settings contain an attribute-breaking payload like: style-1" onmouseover="alert(document.domain)" data-x=" 6. Ensure the site has an OpenWeatherMap API key configured (required for the Weather widget to render its output). 7. Navigate to the frontend page where the widget is displayed; the payload will execute when a user interacts with or views the container div.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.