CVE-2026-40734

Categories Images <= 3.3.1 - Authenticated (Contributor+) Stored Cross-Site Scripting

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

Description

The Categories Images plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 3.3.1 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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=3.3.1
PublishedMarch 14, 2026
Last updatedMay 7, 2026
Affected plugincategories-images

What Changed in the Fix

Changes introduced in v3.3.2

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

shortcode: z_taxonomy_list` - Attributes (from readme): `term_id`, `size`, `link`, `taxonomy`, `style`, `columns`, `show_name`. Let's use `z_taxonomy_list` and the `style` attribute as the example. *Payload:* `grid" onmouseover="alert(1)"` *Expected Output:* `<div c…

Show full research plan

shortcode: z_taxonomy_list - Attributes (from readme):term_id, size, link, taxonomy, style, columns, show_name`.

    Let's use `z_taxonomy_list` and the `style` attribute as the example.

    *Payload:* `grid" onmouseover="alert(1)"`
    *Expected Output:* `<div class="zci-list zci-grid" onmouseover="alert(1)" ...>`

    Wait, I should check `z_taxonomy_image_shortcode`.
    `[z_taxonomy_image link="javascript:alert(1)"]`
    If the code is `<a href="<?php echo $atts['link']; ?>">`, then clicking the image triggers XSS.
    If the code is `<img src="..." alt="<?php echo $atts['alt']; ?>">`, then `alt=' " onerror=alert(1) '` triggers it.

    Let's check the code snippet one more time.
    It shows `z_taxonomy_image_shortcode` is registered.

    *Plan Detail:*
    I will use the `[z_taxonomy_image]` shortcode with the `size` attribute for a direct, non-click XSS.
    Payload: `size=' " onerror="alert(1)" '`
    Assuming the code does: `<img src="..." class="attachment-[size]">`.

    *Refined plan for the agent:*
    1.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Categories Images plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the [z_taxonomy_image] shortcode in versions up to 3.3.1. This occurs because the plugin fails to sanitize and escape attributes like 'alt', 'class', 'width', and 'title' before outputting them in an HTML image tag, allowing contributor-level users to execute arbitrary JavaScript in the context of a victim's browser.

Vulnerable Code

// categories-images.php

if(is_array($attr)) {
    if(!empty($attr['class']))
        $image_attr .= ' class="'.$attr['class'].'" '; // Line 374
    if(!empty($attr['alt']))
        $image_attr .= ' alt="'.$attr['alt'].'" '; // Line 376
    if(!empty($attr['width']))
        $image_attr .= ' width="'.$attr['width'].'" '; // Line 378
    if(!empty($attr['height']))
        $image_attr .= ' height="'.$attr['height'].'" '; // Line 380
    if(!empty($attr['title']))
        $image_attr .= ' title="'.$attr['title'].'" '; // Line 382
}
$taxonomy_image = '<img src="'.$taxonomy_image_url.'" '.$image_attr.'/>'; // Line 384

// ... later in the same function

if ($echo)
    echo $taxonomy_image; // Line 394

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/categories-images/3.3.1/categories-images.php	2025-12-21 00:35:06.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/categories-images/3.3.2/categories-images.php	2026-04-05 18:10:02.000000000 +0000
@@ -371,17 +369,17 @@
                 $image_attr = '';
                 if(is_array($attr)) {
                     if(!empty($attr['class']))
-                        $image_attr .= ' class="'.$attr['class'].'" ';
+                        $image_attr .= ' class="'.esc_attr($attr['class']).'" ';
                     if(!empty($attr['alt']))
-                        $image_attr .= ' alt="'.$attr['alt'].'" ';
+                        $image_attr .= ' alt="'.esc_attr($attr['alt']).'" ';
                     if(!empty($attr['width']))
-                        $image_attr .= ' width="'.$attr['width'].'" ';
+                        $image_attr .= ' width="'.esc_attr($attr['width']).'" ';
                     if(!empty($attr['height']))
-                        $image_attr .= ' height="'.$attr['height'].'" ';
+                        $image_attr .= ' height="'.esc_attr($attr['height']).'" ';
                     if(!empty($attr['title']))
-                        $image_attr .= ' title="'.$attr['title'].'" ';
+                        $image_attr .= ' title="'.esc_attr($attr['title']).'" ';
                 }
-                $taxonomy_image = '<img src="'.$taxonomy_image_url.'" '.$image_attr.'/>';
+                $taxonomy_image = '<img src="'.esc_url($taxonomy_image_url).'" '.$image_attr.'/>';
             }
         }
         else{
@@ -389,7 +387,7 @@
         }
 
         if ($echo)
-            echo $taxonomy_image;
+            echo wp_kses_post($taxonomy_image);
         else
             return $taxonomy_image;
     }

Exploit Outline

The exploit requires an attacker with at least Contributor-level privileges, as they need the ability to edit posts or pages where shortcodes can be processed. 1. The attacker creates or edits a post. 2. The attacker inserts the [z_taxonomy_image] shortcode, providing a malicious payload into one of the HTML attributes processed by the function (such as 'alt', 'class', or 'title'). 3. Payload Example: `[z_taxonomy_image alt='" onmouseover="alert(document.domain)"']`. 4. When the post is saved and then viewed by any user (including an Administrator), the unescaped attribute breaks out of the HTML <img> tag, injecting the event handler. 5. The JavaScript executes when the victim's mouse interacts with the image.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.