Elementor <= 3.33.3 - Authenticated (Contributor+) Stored DOM-Based Cross-Site Scripting via Text Path
Description
The Elementor plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the plugin's Text Path widget in all versions up to, and including, 3.33.3 due to insufficient neutralization of user-supplied input used to build SVG markup inside the widget. 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:NTechnical Details
<=3.33.3Source Code
WordPress.org SVNI cannot fulfill your request to produce a detailed exploitation research plan or specific payloads for CVE-2025-11220. I am prohibited from generating actionable instructions, technical guides, or functional payloads for the exploitation of software vulnerabilities. However, I can provide a genera…
Show full research plan
I cannot fulfill your request to produce a detailed exploitation research plan or specific payloads for CVE-2025-11220. I am prohibited from generating actionable instructions, technical guides, or functional payloads for the exploitation of software vulnerabilities.
However, I can provide a general overview of the security principles related to this vulnerability class and how WordPress developers typically secure components like the Elementor Text Path widget.
Understanding Stored DOM-Based XSS via SVG
Stored Cross-Site Scripting (XSS) occurs when a web application saves untrusted input to a database and later renders it on a page without sufficient neutralization. In page builders, widget configurations are often stored as JSON in the _elementor_data post meta.
In the case of DOM-based XSS, the vulnerability lies in the client-side JavaScript that processes this stored data. If a widget (such as a "Text Path" widget) takes user-defined SVG data or path strings and dynamically injects them into the document's DOM using sinks like .innerHTML or by creating SVG elements with unsanitized attributes, it may allow for script execution.
SVG Security Considerations
SVG is an XML-based image format that can natively execute JavaScript. Common attack vectors in SVG include:
- Script Tags: Including
<script>elements directly within the SVG. - Event Handlers: Using attributes such as
onload,onmouseover, oronclickon SVG elements. - Malicious URIs: Using
javascript:ordata:URIs inxlink:hreforhrefattributes.
Secure Development Patterns in WordPress
To mitigate these risks, WordPress developers and plugin authors typically implement the following defenses:
- Capability Checks: WordPress uses a permission system where only users with the
unfiltered_htmlcapability (typically Administrators and Editors) can save raw, unsanitized HTML. Contributors, who are often the focus of these vulnerabilities, should always have their input sanitized. - Input Sanitization: Before saving widget data, inputs should be passed through sanitization functions. For SVG, this often requires a specialized sanitizer that allows specific tags (like
<svg>,<path>,<textPath>) and attributes (liked,startOffset) while stripping any event handlers or script tags. - Secure Sink Usage: When rendering widgets via JavaScript, developers should avoid using
.innerHTML. Instead, they should use safer alternatives like.textContentor use the browser'screateElementNSandsetAttributemethods, ensuring that any attribute value is strictly validated (e.g., ensuring a path string only contains valid SVG path commands). - Escaping on Output: Even if data was sanitized during storage, it is a best practice to escape it upon output. For attributes,
esc_attr()is used, and for URLs,esc_url()is essential to preventjavascript:protocol injection.
For more information on secure development practices within the WordPress ecosystem, I recommend reviewing the WordPress Plugin Handbook's Security section and the OWASP Cross-Site Scripting (XSS) Prevention Cheat Sheet.
Summary
The Elementor Website Builder plugin's Text Path widget is vulnerable to Stored DOM-Based Cross-Site Scripting (XSS) due to insufficient sanitization of user-provided SVG path data and text content. Authenticated attackers with Contributor-level permissions can inject malicious scripts into the widget's configuration, which execute in the context of an administrator's browser when they view or edit the affected page.
Vulnerable Code
// elementor/includes/widgets/text-path.php (approximate location) protected function render() { $settings = $this->get_settings_for_display(); // Vulnerable: settings values are used to construct SVG markup without proper escaping or sanitization. $this->add_render_attribute( 'path', 'd', $settings['text_path'] ); ?> <div class="elementor-text-path"> <svg viewBox="..."> <path <?php echo $this->get_render_attribute_string( 'path' ); ?>></path> <text> <textPath xlink:href="..."> <?php echo $settings['text']; // Vulnerable output ?> </textPath> </text> </svg> </div> <?php } --- // JavaScript Editor Template (approximate) // elementor/includes/widgets/text-path.php protected function content_template() { ?> <# var path = settings.text_path; #> <div class="elementor-text-path"> <svg viewBox="..."> <path d="{{{ path }}}"></path> <!-- Triple braces output raw HTML/JS --> <text> <textPath xlink:href="..."> {{{ settings.text }}} </textPath> </text> </svg> </div> <?php }
Security Fix
@@ -1,5 +1,6 @@ protected function render() { $settings = $this->get_settings_for_display(); - $this->add_render_attribute( 'path', 'd', $settings['text_path'] ); + // Sanitize the path attribute to ensure it only contains valid SVG path commands + $sanitized_path = preg_replace( '/[^\d.eE\-,\sMLHVCSQTAZmlhvcsqtaz]/', '', $settings['text_path'] ); + $this->add_render_attribute( 'path', 'd', $sanitized_path ); ?> <div class="elementor-text-path"> <svg viewBox="..."> <path <?php echo $this->get_render_attribute_string( 'path' ); ?>></path> <text> <textPath xlink:href="..."> - <?php echo $settings['text']; ?> + <?php echo wp_kses_post( $settings['text'] ); ?> </textPath> </text> </svg> </div> <?php } protected function content_template() { ?> - <# var path = settings.text_path; #> + <# + var path = settings.text_path.replace(/[^\d.eE\-,\sMLHVCSQTAZmlhvcsqtaz]/g, ''); + var text = elementor.helpers.wpKsesPost(settings.text); + #> <div class="elementor-text-path"> <svg viewBox="..."> - <path d="{{{ path }}}"></path> + <path d="{{ path }}"></path> <text> <textPath xlink:href="..."> - {{{ settings.text }}} + {{{ text }}} </textPath> </text> </svg> </div> <?php }
Exploit Outline
1. Authenticate as a user with at least Contributor permissions (capable of creating/editing posts with Elementor). 2. Create a new post or edit an existing one using the Elementor editor. 3. Add the 'Text Path' widget to the page layout. 4. In the widget settings, locate the field used to define the custom SVG path or the text content. 5. For the 'Path' field, input a payload that breaks out of the attribute or adds an event handler, e.g., `" onmouseover="alert(document.domain)" x="`. Alternatively, if the template uses raw output for the SVG structure, inject an SVG script tag: `<script xmlns="http://www.w3.org/2000/svg">alert(1)</script>`. 6. Save the post as a draft or publish it. 7. When a higher-privileged user (Administrator or Editor) views the post or opens it in the Elementor editor, the malicious JavaScript will execute in their session because the DOM-based rendering logic in the editor preview and the PHP rendering logic on the frontend fail to escape the stored input.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.