WF-f80af397-72d5-4446-b43f-3be26657b73e-animation-addons-for-elementor

Animation Addons for Elementor – GSAP Motion Elementor Addons & Website Templates <= 2.6.3 - Authenticated (Contributor+) Stored Cross-Site Scripting

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

Description

The Animation Addons for Elementor – GSAP Motion Elementor Addons & Website Templates plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 2.6.3 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with contributor-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.

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<=2.6.3
PublishedMay 26, 2026
Last updatedJune 1, 2026

What Changed in the Fix

Changes introduced in v2.6.4

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan targets a Stored Cross-Site Scripting (XSS) vulnerability in the **Animation Addons for Elementor** plugin (<= 2.6.3). The vulnerability arises from the plugin's failure to escape post-related data (specifically titles) when rendered through its Elementor widgets. --- ### 1. Vul…

Show full research plan

This research plan targets a Stored Cross-Site Scripting (XSS) vulnerability in the Animation Addons for Elementor plugin (<= 2.6.3). The vulnerability arises from the plugin's failure to escape post-related data (specifically titles) when rendered through its Elementor widgets.


1. Vulnerability Summary

  • Vulnerability: Authenticated (Contributor+) Stored Cross-Site Scripting
  • Location: inc/AAE_Post_Handler_Trait.php within the render_title() and wcf_wrap_first_n_words() functions.
  • Cause: The plugin retrieves post titles using get_the_title() and processes them through wcf_wrap_first_n_words(). This function wraps parts of the title in a <span> tag but returns the raw, unescaped string, which is then echoed directly to the page.
  • Impact: A user with Contributor-level permissions can create a post with a malicious title containing JavaScript. When an administrator or any visitor views a page where an Animation Addons widget (like "Post Grid" or "Loop Grid") displays that post, the script executes in their browser context.

2. Attack Vector Analysis

  • Entry Point: WordPress Post Title.
  • Vulnerable Parameter: post_title.
  • Authentication Level: Contributor or higher (anyone capable of creating/editing posts).
  • Preconditions: The site must have at least one page using an Animation Addons widget that renders post titles (e.g., Loop Grid, Post Grid).

3. Code Flow

  1. Source: A Contributor creates/edits a post. The malicious payload is saved in the wp_posts table under post_title.
  2. Sink Path:
    • An Elementor widget using the AAE_Post_Handler_Trait (e.g., a Post Grid widget) is rendered on the frontend.
    • The widget calls $this->render_title() (defined in inc/AAE_Post_Handler_Trait.php).
    • Inside render_title(), the code fetches the title: $title = $this->trim_words( get_the_title(), $max_length );.
    • It then calls echo $this->wcf_wrap_first_n_words( $title, $highlight_title_length );.
    • The Sink: wcf_wrap_first_n_words() (also in inc/AAE_Post_Handler_Trait.php) manipulates the string and returns it:
      return '<span class="' . $class . '">' . $text . '</span>';
      
    • Because $text (the title) is never passed through esc_html(), the payload is executed.

4. Nonce Acquisition Strategy

This exploit leverages the standard WordPress post creation/editing mechanism. No plugin-specific AJAX nonces are required for the primary payload injection via the post title.

However, if the environment requires extracting a nonce to verify widget rendering or to interact with the Elementor Editor (if the Contributor is editing a page directly), the following applies:

  • Variable Name: WCF_Addons_Editor (found in class-plugin.php).
  • Nonce Key: _wpnonce.
  • Extraction Method:
    1. Create a page: wp post create --post_type=page --post_status=publish --post_content='[any_shortcode]'
    2. Navigate to the editor for that page.
    3. Run: browser_eval("window.WCF_Addons_Editor?._wpnonce").

5. Exploitation Strategy

  1. Log in as Contributor.
  2. Create a Malicious Post: Use the http_request tool to create a post with a script payload in the title.
  3. Ensure Rendering: Use the wp-cli to ensure at least one page exists that contains an Animation Addons widget.
  4. Trigger Execution: Access the page as an Admin user.

Payload Request

POST /wp-admin/post.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded

action=editpost&post_ID=[POST_ID]&post_title=Test <img src=x onerror=alert(document.domain)>&post_status=publish

6. Test Data Setup

  1. User: A user with the contributor role.
  2. Vulnerable Post: A post created by the contributor with the payload: "><script>alert('XSS')</script>.
  3. Display Page: A published page containing an Animation Addons widget that renders recent posts.
    • Note: If no such page exists, create one via WP-CLI using a known widget slug from config.php (e.g., a Post Grid or Loop Grid).

7. Expected Results

  • When viewing the page containing the widget, the browser should render:
    <span class="highlight">Test <img src=x onerror=alert(document.domain)></span>
  • The onerror event will trigger, and an alert box displaying the document domain will appear.

8. Verification Steps

  1. Check Database: wp db query "SELECT post_title FROM wp_posts WHERE post_title LIKE '%<img%'".
  2. Inspect Response: Use http_request (GET) to the page and verify that the raw payload string exists inside a <span> tag with the class wcf-post-title.

9. Alternative Approaches

  • Read More XSS: The render_read_more() function uses wp_kses_post( $read_more ). While wp_kses_post is generally safe, it allows some HTML. Check if attributes or specific tags can be abused if the Contributor can modify the widget settings directly within Elementor.
  • Widget Settings: If a Contributor has access to the Elementor editor, they can inject payloads into widget-specific controls (e.g., "Image Box Title"). If these are rendered via a similar path without esc_html, they are equally vulnerable. Look for the render() method in the widget classes (e.g., WCF_ADDONS\Widgets\Image_Box).
Research Findings
Static analysis — not yet PoC-verified

Summary

The Animation Addons for Elementor plugin is vulnerable to Stored Cross-Site Scripting via post titles rendered in various Elementor widgets. Authenticated attackers with Contributor-level access or higher can inject malicious scripts into post titles, which are then rendered and executed without escaping when viewed by other users, including administrators.

Vulnerable Code

// inc/AAE_Post_Handler_Trait.php

function wcf_wrap_first_n_words( $text, $n, $class = 'highlight' ) {
    // Split the text into an array of words
    $words = explode( ' ', $text );
    // Check if the text has enough words to wrap
    if ( count( $words ) >= $n ) {
        // Extract the first N words and wrap them in a span tag
        $wrapped_words   = array_slice( $words, 0, $n );
        $remaining_words = array_slice( $words, $n );
        // Create the wrapped portion
        $wrapped = '<span class="' . $class . '">' . implode( ' ', $wrapped_words ) . '</span>';

        // Combine the wrapped portion with the remaining words
        return $wrapped . ' ' . implode( ' ', $remaining_words );
    }

    // If there are fewer words than N, wrap the whole text
    return '<span class="' . $class . '">' . $text . '</span>';
}

---

// inc/AAE_Post_Handler_Trait.php line 51
$title                  = $this->trim_words( get_the_title(), $max_length );
$highlight_title_length = (int) $this->get_settings( 'highlight_title_length' );

echo $this->wcf_wrap_first_n_words( $title, $highlight_title_length ); // Wrap first 2 words

Security Fix

--- a/inc/AAE_Post_Handler_Trait.php
+++ b/inc/AAE_Post_Handler_Trait.php
@@ -24,11 +24,11 @@
 			$wrapped_words   = array_slice( $words, 0, $n );
 			$remaining_words = array_slice( $words, $n );
 			// Create the wrapped portion
-			$wrapped = '<span class="' . $class . '">' . implode( ' ', $wrapped_words ) . '</span>';
+			$wrapped = '<span class="' . esc_attr( $class ) . '">' . esc_html( implode( ' ', $wrapped_words ) ) . '</span>';
 
 			// Combine the wrapped portion with the remaining words
-			return $wrapped . ' ' . implode( ' ', $remaining_words );
+			return $wrapped . ' ' . esc_html( implode( ' ', $remaining_words ) );
 		}
 
 		// If there are fewer words than N, wrap the whole text
-		return '<span class="' . $class . '">' . $text . '</span>';
+		return '<span class="' . esc_attr( $class ) . '">' . esc_html( $text ) . '</span>';
 	}

Exploit Outline

The exploit is achieved by an authenticated user (Contributor or higher) following these steps: 1. Log in to the WordPress admin dashboard and create a new post. 2. Set the post title to a malicious JavaScript payload (e.g., `"><img src=x onerror=alert(1)>`). 3. Publish or save the post. 4. Ensure there is a page on the site utilizing an Animation Addons widget that renders recent posts (such as a Post Grid, Loop Grid, or Archive widget). 5. When an administrator or any other user views the page containing the widget, the plugin calls `wcf_wrap_first_n_words()` via `AAE_Post_Handler_Trait`, which returns the unescaped payload wrapped in a `<span>` tag. The payload is then echoed directly into the page content, triggering the execution of the script in the victim's browser.

Check if your site is affected.

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