
CVE-2026-16540 — Simply Schedule Appointments < 1.6.12.6 Divulgazione non autenticata dei dati degli appuntamenti e cancellazione di massa
| Campo | Dettagli |
|---|
| CVE | CVE-2026-16540 |
| Plugin | Simply Schedule Appointments |
| Versioni interessate | < 1.6.12.6 |
| Corretto nella versione | 1.6.12.6 |
| Installazioni attive | ~70.000 |
| CVSS 3.1 | 6.5 (Medio) — CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N |
| CWE | CWE-863 (Autorizzazione errata) |
| OWASP | A5: Controllo degli accessi non funzionante |
| WPVDB | c3829294-c388-4151-9e25-a3eac7b1f1c6 |
| Ricercatore | Suleyman Huseynov (@huseyn0vs__) |
| Divulgazione | 2026-07-22 |
L'endpoint REST GET /wp-json/ssa/v1/appointments/purge in Simply Schedule Appointments applica un controllo di autorizzazione (get_items_permissions_check) che convalida un id_token attestante la proprietà di un singolo appuntamento. Tuttavia, il gestore (purge_appointments()) ignora completamente l'appuntamento a cui appartiene il token e opera invece su tutti gli appuntamenti dell'intero sito che corrispondono alle condizioni fornite.
Un attaccante non autenticato che prenota un qualsiasi singolo appuntamento tramite il modulo di prenotazione pubblico riceve un id_token. Usando quel token, l'attaccante può:
La cancellazione si propaga a cascata su 6 tabelle di database dipendenti in transazioni committate, senza alcuna funzionalità di annullamento nativa.
File: includes/class-appointment-model.php
Il controllo dei permessi e il gestore operano su ambiti completamente diversi:
// Registrazione della route
register_rest_route( $namespace, '/' . $base . '/purge', array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'purge_appointments' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
),
) );
Controllo dei permessi — verifica la proprietà di UN appuntamento tramite id_token:
public function get_items_permissions_check( $request ) {
// ...
if ( true === $this->id_token_permissions_check( $request ) ) {
return true; // concede l'accesso se il chiamante dimostra la proprietà di un appuntamento
}
// ...
}
Gestore — ignora l'appuntamento del token e opera sull'intero sito:
public function purge_appointments( WP_REST_Request $request ) {
$params = $request->get_params();
// Nessuna limitazione per customer_id o appointment_id — elimina TUTTI gli appuntamenti corrispondenti
if ( isset( $params['purge_past_appointments'] ) && 'true' === $params['purge_past_appointments'] ) {
$conditions[] = $wpdb->prepare( 'end_date < %s', $date_modified_max->format( 'Y-m-d' ) );
}
$sql = 'SELECT * FROM ' . $this->get_table_name()
. ' WHERE ' . implode( ' OR ', $conditions )
. ' ORDER BY id ASC LIMIT 5000';
$list = $wpdb->get_results( $sql, ARRAY_A );
// Cancellazione a cascata su 6 tabelle in transazioni committate
}
L'id_token è un HMAC-MD5 derivato da id e date_created di un singolo appuntamento. Il possesso di questo token dimostra solo che il chiamante ha prenotato uno specifico appuntamento — non conferisce alcun privilegio a livello di sito.
1. L'attaccante visita la pagina di prenotazione e prenota un qualsiasi appuntamento gratuito
→ riceve un'email di conferma contenente: appointment_id + id_token
2. GET /wp-json/ssa/v1/appointments/purge
?id=<appointment_id>
&token=<id_token>
&purge_past_appointments=true
3. Il controllo dei permessi viene superato (token valido per l'appuntamento dell'attaccante)
4. Il gestore seleziona TUTTI gli appuntamenti passati dell'intero sito → restituisce PII nella risposta
→ li elimina definitivamente su 6 tabelle (nelle edizioni premium)
Il PoC sarà pubblicato il 2026-08-05 al termine dell'embargo di divulgazione coordinata.
Vedi la directory poc/ dopo la data di fine embargo.
| Scenario | Risultato |
|---|---|
| Divulgazione dei dati | Nomi, email, numeri di telefono, dettagli degli appuntamenti di tutti i clienti |
| Cancellazione di massa (premium) | Tutti gli appuntamenti storici/futuri distrutti definitivamente su 6 tabelle |
| Nessuna via di recupero | È necessario il ripristino completo del backup del database |
| Data | Evento |
|---|---|
| 2026-07-10 | Vulnerabilità scoperta |
| 2026-07-10 | Inviata a WPScan |
| 2026-07-22 | CVE-2026-16540 assegnato |
| 2026-07-22 | Divulgazione pubblica su WPScan |
| 2026-08-05 | PoC pubblicato |