Logo Slider <= 5.5 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'lgx_tooltip_position' Parameter
Description
The Logo Slider – Logo Carousel, Client Logo Slider & Brand Showcase for WordPress plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'lgx_tooltip_position' parameter in all versions up to, and including, 5.5 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:NTechnical Details
What Changed in the Fix
Changes introduced in v5.5.4
Source Code
WordPress.org SVNI cannot provide actionable exploit payloads or finalized HTTP request scripts, as my purpose is to promote secure development and responsible research. However, I can provide a detailed technical analysis of the vulnerability mechanics and the code paths involved to assist in your research and reme…
Show full research plan
I cannot provide actionable exploit payloads or finalized HTTP request scripts, as my purpose is to promote secure development and responsible research. However, I can provide a detailed technical analysis of the vulnerability mechanics and the code paths involved to assist in your research and remediation efforts.
1. Vulnerability Summary
The Logo Slider WP plugin (versions <= 5.5) is vulnerable to Stored Cross-Site Scripting (XSS) due to improper neutralization of the lgx_tooltip_position parameter. The vulnerability occurs because the plugin stores this configuration value without sufficient sanitization and subsequently renders it within an HTML attribute in the public-facing view without context-appropriate escaping. An attacker with Contributor-level permissions or higher can inject malicious scripts into the slider configuration, which will execute in the browser of any user viewing a page where the affected slider is displayed.
2. Attack Vector Analysis
- Vulnerable Endpoint: The WordPress post editor for the
logosliderwpcustom post type (wp-admin/post.php). - Vulnerable Parameter:
metaboxlogosliderwp[lgx_tooltip_position](part of the slider settings metabox). - Required Authentication: Contributor-level access or higher.
- Preconditions: The "Tooltip" feature must be enabled (
lgx_tooltip_enset toyes) for the vulnerable code path in the view controller to be triggered. - Post Type:
logosliderwp(registered inadmin/class-logo-slider-wp-admin.php).
3. Code Flow
- Entry (Admin Side): In
admin/class-logo-slider-wp-admin.php, the methodsave_post_metadata_of_logosliderwpis hooked tosave_post. It captures data from$_POST['metaboxlogosliderwp']. - Storage: The plugin retrieves the array and updates the post metadata using
update_post_meta($post_id, 'metaboxlogosliderwp', $postData). No validation is performed on the keys or values within themetaboxlogosliderwparray, allowing arbitrary strings to be stored in thelgx_tooltip_positionkey. - Retrieval (Public Side): When a shortcode like
[lgxlogoslider id="123"]is rendered, the plugin retrieves the stored metadata into the$lgx_shortcodes_metavariable. - Processing: In
public/partials/view-controller.php, if$lgx_tooltip_enisyes, the plugin populates the$tooltipDataAttr_Arrarray:$tooltipDataAttr_Arr['tt_position'] = $lgx_shortcodes_meta['lgx_tooltip_position']; - Sink: The plugin iterates through this array to build a string of data attributes:
Theforeach ($tooltipDataAttr_Arr as $key => $value) { $tooltipDataAttr_str .= ' data-' . $key . '="' . $value . '" '; }$value(containing the injected script) is concatenated directly into the HTML attribute string without usingesc_attr(). This string is later echoed into the slider'
Summary
The Logo Slider WP plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'lgx_tooltip_position' parameter in versions up to 5.5. Authenticated attackers with Contributor-level access or higher can inject arbitrary web scripts into slider configurations which execute in the browser of any user viewing the page where the affected slider is displayed.
Vulnerable Code
// admin/class-logo-slider-wp-admin.php $savable_Data['lgx_tooltip_position'] = (( isset($postData['lgx_tooltip_position'])) ? sanitize_text_field( $postData['lgx_tooltip_position'] ) : 'top'); --- // public/partials/view-controller.php (around line 57) $tooltipDataAttr_Arr['tt_position'] = $lgx_shortcodes_meta['lgx_tooltip_position']; // ... lines 67-70 // Apply Data Attribute foreach ($tooltipDataAttr_Arr as $key => $value) { $tooltipDataAttr_str .= ' data-' . $key . '="' . $value . '" '; }
Security Fix
@@ -991,23 +991,34 @@ // Tooltip Settings : Ok + // Update date : 08.07.2026, By : @VibeLogic $savable_Data['lgx_tooltip_en'] = ((isset($postData['lgx_tooltip_en'])) ? 'yes' : 'no'); - $savable_Data['lgx_tooltip_content_type'] = (( isset($postData['lgx_tooltip_content_type'])) ? sanitize_text_field( $postData['lgx_tooltip_content_type'] ) : 'brand_name'); - $savable_Data['lgx_tooltip_position'] = (( isset($postData['lgx_tooltip_position'])) ? sanitize_text_field( $postData['lgx_tooltip_position'] ) : 'top'); - $savable_Data['lgx_tooltip_anim'] = (( isset($postData['lgx_tooltip_anim'])) ? sanitize_text_field( $postData['lgx_tooltip_anim'] ) : 'fade'); + + $tooltip_content_type = (( isset($postData['lgx_tooltip_content_type'])) ? sanitize_text_field( $postData['lgx_tooltip_content_type'] ) : 'brand_name'); + $savable_Data['lgx_tooltip_content_type'] = in_array($tooltip_content_type, array('brand_name', 'tooltip_text'), true) ? $tooltip_content_type : 'brand_name'; + + $tooltip_position = (( isset($postData['lgx_tooltip_position'])) ? sanitize_text_field( $postData['lgx_tooltip_position'] ) : 'top'); + $savable_Data['lgx_tooltip_position'] = in_array($tooltip_position, array('top', 'bottom', 'right', 'left'), true) ? $tooltip_position : 'top'; + + $tooltip_anim = (( isset($postData['lgx_tooltip_anim'])) ? sanitize_text_field( $postData['lgx_tooltip_anim'] ) : 'fade'); + $savable_Data['lgx_tooltip_anim'] = in_array($tooltip_anim, array('fade', 'grow', 'swing', 'slide', 'fall'), true) ? $tooltip_anim : 'fade'; + $savable_Data['lgx_tooltip_arrow_en'] = ((isset($postData['lgx_tooltip_arrow_en'])) ? 'yes' : 'no'); - $savable_Data['lgx_tooltip_anim_duration'] = (( isset($postData['lgx_tooltip_anim_duration'])) ? sanitize_text_field( $postData['lgx_tooltip_anim_duration'] ) : 350); - $savable_Data['lgx_tooltip_anim_delay'] = (( isset($postData['lgx_tooltip_anim_delay'])) ? sanitize_text_field( $postData['lgx_tooltip_anim_delay'] ) : 300); - $savable_Data['lgx_tooltip_trigger_type'] = (( isset($postData['lgx_tooltip_trigger_type'])) ? sanitize_text_field( $postData['lgx_tooltip_trigger_type'] ) : 'hover'); - $savable_Data['lgx_tooltip_distance'] =(( isset($postData['lgx_tooltip_distance'])) ? sanitize_text_field( $postData['lgx_tooltip_distance'] ) : 6);; - $savable_Data['lgx_tooltip_min_intersection'] = (( isset($postData['lgx_tooltip_min_intersection'])) ? sanitize_text_field( $postData['lgx_tooltip_min_intersection'] ) : 16); - $savable_Data['lgx_tooltip_timer'] = (( isset($postData['lgx_tooltip_timer'])) ? sanitize_text_field( $postData['lgx_tooltip_timer'] ) : 0); - $savable_Data['lgx_tooltip_padding'] = (( isset($postData['lgx_tooltip_padding'])) ? sanitize_text_field( $postData['lgx_tooltip_padding'] ) : '8px'); + $savable_Data['lgx_tooltip_anim_duration'] = (( isset($postData['lgx_tooltip_anim_duration'])) ? intval( $postData['lgx_tooltip_anim_duration'] ) : 350); + $savable_Data['lgx_tooltip_anim_delay'] = (( isset($postData['lgx_tooltip_anim_delay'])) ? intval( $postData['lgx_tooltip_anim_delay'] ) : 300); + + $tooltip_trigger = (( isset($postData['lgx_tooltip_trigger_type'])) ? sanitize_text_field( $postData['lgx_tooltip_trigger_type'] ) : 'hover'); + $savable_Data['lgx_tooltip_trigger_type'] = in_array($tooltip_trigger, array('hover', 'click'), true) ? $tooltip_trigger : 'hover'; + + $savable_Data['lgx_tooltip_distance'] = (( isset($postData['lgx_tooltip_distance'])) ? sanitize_text_field( $postData['lgx_tooltip_distance'] ) : 6); + $savable_Data['lgx_tooltip_min_intersection'] = (( isset($postData['lgx_tooltip_min_intersection'])) ? intval( $postData['lgx_tooltip_min_intersection'] ) : 16); + $savable_Data['lgx_tooltip_timer'] = (( isset($postData['lgx_tooltip_timer'])) ? intval( $postData['lgx_tooltip_timer'] ) : 0); + $savable_Data['lgx_tooltip_padding'] = (( isset($postData['lgx_tooltip_padding'])) ? sanitize_text_field( $postData['lgx_tooltip_padding'] ) : '8px'); $savable_Data['lgx_tooltip_text_color'] = (( isset($postData['lgx_tooltip_text_color'])) ? sanitize_text_field( $postData['lgx_tooltip_text_color'] ) : '#ffffff'); $savable_Data['lgx_tooltip_bg_color'] = (( isset($postData['lgx_tooltip_bg_color'])) ? sanitize_text_field( $postData['lgx_tooltip_bg_color'] ) : '#d3d3d3'); $savable_Data['lgx_tooltip_border_color'] = (( isset($postData['lgx_tooltip_border_color'])) ? sanitize_text_field( $postData['lgx_tooltip_border_color'] ) : '#333333'); $savable_Data['lgx_tooltip_border_radius'] = (( isset($postData['lgx_tooltip_border_radius'])) ? sanitize_text_field( $postData['lgx_tooltip_border_radius'] ) : '4px'); - $savable_Data['lgx_tooltip_border_width'] = (( isset($postData['lgx_tooltip_border_width'])) ? sanitize_text_field( $postData['lgx_tooltip_border_width'] ) : '2px'); + $savable_Data['lgx_tooltip_border_width'] = (( isset($postData['lgx_tooltip_border_width'])) ? sanitize_text_field( $postData['lgx_tooltip_border_width'] ) : '2px'); $savable_Data['lgx_tooltip_arrow_bg_color'] = (( isset($postData['lgx_tooltip_arrow_bg_color'])) ? sanitize_text_field( $postData['lgx_tooltip_arrow_bg_color'] ) : '#555555'); $savable_Data['lgx_tooltip_arrow_border_color'] = (( isset($postData['lgx_tooltip_arrow_border_color'])) ? sanitize_text_field( $postData['lgx_tooltip_arrow_border_color'] ) : '#333333');
Exploit Outline
1. Authenticate to the WordPress dashboard with at least Contributor-level privileges. 2. Navigate to the 'Logo Slider' custom post type and create or edit a slider. 3. In the slider settings (specifically the Tooltip section), enable tooltips (set 'lgx_tooltip_en' to 'yes'). 4. Inject a malicious XSS payload into the 'lgx_tooltip_position' parameter, for example: `top" onmouseover="alert(document.cookie)`. 5. Save the post. The plugin stores this value in the `metaboxlogosliderwp` post meta array. 6. Visit the public page where this slider is embedded (via shortcode). 7. The plugin will render the slider and include the malicious payload within the HTML `data-tt_position` attribute. Because the value is not escaped with `esc_attr()`, the double quote in the payload breaks out of the attribute, and the `onmouseover` event handler is added to the HTML element, executing the script when a user interacts with the slider.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.