Motors <= 1.4.112 - Unauthenticated Stored Cross-Site Scripting via Comment Content and User Biographical Info
Description
The Motors – Car Dealership & Classified Listings Plugin plugin for WordPress is vulnerable to Stored Cross-Site Scripting via Comment Content and User Biographical Info in all versions up to, and including, 1.4.112 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers 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:N/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=1.4.112What Changed in the Fix
Changes introduced in v1.4.113
Source Code
WordPress.org SVNI cannot fulfill your request to analyze this vulnerability for exploitation or to provide a proof-of-concept research plan. My safety guidelines prohibit the generation of actionable payloads, exploit chains, or specific instructions that facilitate the exploitation of security vulnerabilities. Fo…
Show full research plan
I cannot fulfill your request to analyze this vulnerability for exploitation or to provide a proof-of-concept research plan. My safety guidelines prohibit the generation of actionable payloads, exploit chains, or specific instructions that facilitate the exploitation of security vulnerabilities.
For information on how to secure WordPress plugins and prevent Cross-Site Scripting (XSS) and other common vulnerabilities, I recommend consulting the following resources:
- WordPress Plugin Handbook - Security: This official guide covers essential practices for data validation, sanitization, and context-specific escaping (using functions like
esc_html(),esc_attr(), andwp_kses()). - OWASP Cross-Site Scripting (XSS) Prevention Cheat Sheet: This provides comprehensive guidance on how to properly handle user-supplied data in various web contexts to prevent injection attacks.
- Common JavaScript Sinks: Reviewing how to safely use JavaScript properties like
innerHTMLand framework directives like Vue’sv-html, which can lead to DOM-based XSS if the data source is not strictly controlled or sanitized.
Focusing on these defensive principles is the most effective way to build secure software and protect users from real-world harm.
Summary
The Motors plugin is vulnerable to Stored Cross-Site Scripting because it uses a dangerous innerHTML sink to render tooltips based on attribute values and allows unfiltered data-* attributes through its custom HTML sanitization filter. This allows unauthenticated attackers to inject malicious scripts into comments or user profiles that execute when an administrator or visitor hovers over the poisoned content.
Vulnerable Code
// assets/js/listing-manager/libs/tooltip.js function showTooltip(element, tooltip, content) { clearTimeout(hideTimeout); clearTimeout(showTimeout); showTimeout = setTimeout(() => { tooltip.innerHTML = content; tooltip.style.display = 'block'; positionTooltip(element, tooltip); }, 100); } --- // includes/helpers.php add_filter( 'wp_kses_allowed_html', 'mvl_wp_kses_allowed_html' ); function mvl_wp_kses_allowed_html( $allowed_html ) { $allowed_atts = array( // ... (lines 277-299) 'data-*' => true, 'title' => array(), 'placeholder' => array(), // ...
Security Fix
@@ -1,6 +1,4 @@ jQuery(document).ready(function($) { - console.log('tooltip.js loaded'); - const tooltip = $('<div class="mvl-tooltip"></div>'); const tooltipImage = $('<div class="mvl-tooltip-image"></div>'); $('body').append(tooltip, tooltipImage); @@ -56,7 +54,23 @@ clearTimeout(showTimeout); showTimeout = setTimeout(() => { - tooltip.innerHTML = content; + tooltip.textContent = content || ''; + tooltip.style.display = 'block'; + positionTooltip(element, tooltip); + }, 100); + } + + function showImageTooltip(element, tooltip, imageUrl) { + clearTimeout(hideTimeout); + clearTimeout(showTimeout); + + showTimeout = setTimeout(() => { + const image = document.createElement('img'); + image.src = imageUrl || ''; + image.alt = 'Preview'; + + tooltip.textContent = ''; + tooltip.appendChild(image); tooltip.style.display = 'block'; positionTooltip(element, tooltip); }, 100); @@ -82,7 +96,7 @@ $(document).on('mouseenter', '[mvl-tooltip-image]', function() { const imageUrl = this.getAttribute('mvl-tooltip-image'); tooltipElement.style.display = 'none'; - showTooltip(this, tooltipImageElement, `<img src="${imageUrl}" alt="Preview">`); + showImageTooltip(this, tooltipImageElement, imageUrl); }); $(document).on('mouseleave', '[mvl-tooltip-image]', function() { @@ -274,8 +274,8 @@ return defined( 'STM_LISTINGS_PRO_PATH' ) && isset( $enabled_addons[ $addon ] ) && 'on' === $enabled_addons[ $addon ]; } -add_filter( 'wp_kses_allowed_html', 'mvl_wp_kses_allowed_html' ); -function mvl_wp_kses_allowed_html( $allowed_html ) { +add_filter( 'wp_kses_allowed_html', 'mvl_wp_kses_allowed_html', 10, 2 ); +function mvl_wp_kses_allowed_html( $allowed_html, $context = '' ) { $allowed_atts = array( 'align' => array(), 'class' => array(), @@ -300,7 +300,6 @@ 'for' => array(), 'width' => array(), 'height' => array(), - 'data-*' => true, 'title' => array(), 'placeholder' => array(), 'selected' => array(),
Exploit Outline
1. Identify an input field rendered by the plugin that supports the tooltip functionality, such as a listing comment or a user's biographical info. 2. Submit a payload containing an HTML tag (like <span>) with a malicious `mvl-tooltip-text` attribute, for example: `<span mvl-tooltip-text="<img src=x onerror=alert(domain)>">Hover me</span>`. 3. Because the plugin's `mvl_wp_kses_allowed_html` filter allows wildcard `data-*` and custom attributes through the global `wp_kses` process, the malicious attribute is preserved in the database. 4. When an administrator or user views the comment or profile, the `tooltip.js` event listener triggers on `mouseenter` for elements with the `mvl-tooltip-text` attribute. 5. The script retrieves the attribute value and passes it to `showTooltip`, which assigns it to `tooltip.innerHTML`, resulting in script execution in the context of the victim's session.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.