CVE-2026-10104

Product Video Gallery for Woocommerce <= 1.5.1.8 - Authenticated (Shop Manager+) Stored Cross-Site Scripting via custom_thumbnail Parameter

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

Description

The Product Video Gallery for Woocommerce plugin for WordPress is vulnerable to Stored Cross-Site Scripting via custom_thumbnail Parameter in all versions up to, and including, 1.5.1.8 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with shop manager-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:H/PR:H/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
High
Privileges Required
High
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.5.1.8
PublishedJuly 1, 2026
Last updatedJuly 2, 2026

What Changed in the Fix

Changes introduced in v1.5.1.9

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

I cannot fulfill your request to produce a detailed exploitation research plan or actionable payloads for this vulnerability. I can, however, explain the mechanics of Stored Cross-Site Scripting (XSS) within WordPress plugins and the standard defensive practices used to mitigate such risks. ### Mec…

Show full research plan

I cannot fulfill your request to produce a detailed exploitation research plan or actionable payloads for this vulnerability. I can, however, explain the mechanics of Stored Cross-Site Scripting (XSS) within WordPress plugins and the standard defensive practices used to mitigate such risks.

Mechanics of Stored XSS in WordPress

Stored XSS occurs when a web application receives data from a user, stores it in a persistent database (like WordPress's wp_options or wp_postmeta tables), and later renders that data in a web page without sufficient sanitization or escaping.

In the context of WordPress plugins, this often happens during the following cycle:

  1. Input Collection: A plugin provides an interface (e.g., a settings page or a custom field on a post/product edit screen) where a user can enter data.
  2. Persistence: The data is saved using functions like update_option(), update_post_meta(), or update_user_meta(). If the plugin does not sanitize the input (e.g., using sanitize_text_field()), malicious HTML or JavaScript may be stored in the database.
  3. Rendering: When the data is subsequently retrieved (e.g., using get_option() or get_post_meta()) and displayed on the frontend or in the admin dashboard, it must be escaped. If the output is echoed directly without using an escaping function, any stored scripts will execute in the browser of the user viewing the page.

Defensive Best Practices

To prevent Stored XSS, developers are encouraged to follow the principle of "sanitizing on input and escaping on output."

Sanitization on Input

Before saving data to the database, it should be cleaned based on the expected data type.

  • Text fields: Use sanitize_text_field() to strip tags and line breaks.
  • HTML content: If HTML is intentionally allowed, use wp_kses() or wp_kses_post() to whitelist specific tags and attributes.
  • URLs: Use esc_url_raw() for URLs intended for database storage.

Escaping on Output

Data retrieved from the database must be escaped immediately before being rendered in the HTML context.

  • HTML Body: Use esc_html() for data that will be inside an HTML tag.
  • HTML Attributes: Use esc_attr() for data placed inside an attribute (e.g., value="..." or title="...").
  • URLs: Use esc_url() for href or src attributes.
  • JavaScript Variables: When passing data from PHP to JavaScript, use wp_json_encode() or wp_localize_script() to ensure the data is safely encoded as a JSON object.

Identification and Remediation

Security researchers typically identify these issues by tracing the data flow from "sinks" (where data is output) back to "sources" (where data is input). Remediation involves identifying the missing sanitization or escaping functions in the code and applying the appropriate WordPress security functions.

For further information on securing WordPress plugins, you can consult the WordPress Plugin Handbook's Security section and the OWASP Top Ten project.

Research Findings
Static analysis — not yet PoC-verified

Summary

The Product Video Gallery for Woocommerce plugin is vulnerable to Stored Cross-Site Scripting via the 'custom_thumbnail' parameter due to insufficient output escaping in the product gallery rendering logic. Authenticated attackers with Shop Manager or Admin privileges can inject malicious scripts into product video metadata, which execute whenever a user views the affected product page.

Vulnerable Code

// public/class-rendering.php around line 351
public function nickx_get_video_thumbanil_html( $product_id, $thumbnail_size ) {
    // ...
    $custom_thumbnails      = get_post_meta( $product_id, '_nickx_video_custom_thumbnail', true );
    // ...
    foreach ($product_video_urls as $key => $product_video_url) {
        if( !empty( $product_video_url ) ) {
            $product_video_thumb_id   = isset($product_video_thumb_ids[$key]) ? $product_video_thumb_ids[$key] : '';
            // Line 366: custom_thumbnails[$key] is used without escaping inside an attribute string
            $custom_thumbnail        = isset($custom_thumbnails[$key]) && !empty($product_video_thumb_id) ? 'custom_thumbnail="'.$custom_thumbnails[$key].'"' : '';
            // ...
            echo apply_filters( 'woocommerce_single_product_image_thumbnail_html', '<div class="nswiper-slide nickx-thumbnail product_thumbnail_item '.$custom_thumbnail.'" ...

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/product-video-gallery-slider-for-woocommerce/1.5.1.8/public/class-rendering.php	2026-05-20 16:20:18.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/product-video-gallery-slider-for-woocommerce/1.5.1.9/public/class-rendering.php	2026-06-30 15:59:08.000000000 +0000
@@ -363,7 +377,7 @@
 					foreach ($product_video_urls as $key => $product_video_url) {
 						if( !empty( $product_video_url ) ) {
 							$product_video_thumb_id   = isset($product_video_thumb_ids[$key]) ? $product_video_thumb_ids[$key] : '';
-							$custom_thumbnail        = isset($custom_thumbnails[$key]) && !empty($product_video_thumb_id) ? 'custom_thumbnail="'.$custom_thumbnails[$key].'"' : '';
+							$custom_thumbnail        = isset($custom_thumbnails[$key]) && !empty($product_video_thumb_id) ? 'custom_thumbnail="' . esc_attr($custom_thumbnails[$key]) . '"' : '';
 							$product_video_thumb_url = $wc_placeholder_img;
 							$global_thumb = '';
 							if ( $product_video_thumb_id ) {

Exploit Outline

The exploit target is the WooCommerce product edit screen. An attacker with 'Shop Manager' or higher privileges can modify a product's video gallery settings. Specifically, by manipulating the post meta field associated with custom thumbnails (likely via the plugin's meta box in the admin dashboard), the attacker provides a payload such as `" onmouseover="alert(document.cookie)" style="width:1000px;height:1000px;display:block;"`. When the product page is viewed on the frontend, the `nickx_get_video_thumbanil_html` function retrieves this meta value and echoes it directly into a `div` element's `custom_thumbnail` attribute without using `esc_attr()`. This allows the attacker to break out of the attribute and execute arbitrary JavaScript 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.