
CVE-2026-16540 — Simply Schedule Appointments < 1.6.12.6 Divulgation non authentifiée des données de rendez-vous et suppression massive
purge| Champ | Détails |
|---|---|
| CVE | CVE-2026-16540 |
| Extension | Simply Schedule Appointments |
| Versions concernées | < 1.6.12.6 |
| Corrigé dans | 1.6.12.6 |
| Installations actives | ~70,000 |
| CVSS 3.1 | 6.5 (Moyen) — CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N |
| CWE | CWE-863 (Autorisation incorrecte) |
| OWASP | A5 : Contrôle d'accès cassé |
| WPVDB | c3829294-c388-4151-9e25-a3eac7b1f1c6 |
| Chercheur | Suleyman Huseynov (@huseyn0vs__) |
| Divulgué | 2026-07-22 |
L'endpoint REST GET /wp-json/ssa/v1/appointments/purge de Simply Schedule Appointments applique un contrôle d'autorisation (get_items_permissions_check) qui valide un id_token prouvant la possession d'un seul rendez-vous. Cependant, le gestionnaire (purge_appointments()) ignore complètement à quel rendez-vous le jeton est associé et agit à la place sur tous les rendez-vous du site correspondant aux conditions fournies.
Un attaquant non authentifié qui réserve un seul rendez-vous via le formulaire de réservation public reçoit un id_token. Grâce à ce jeton, l'attaquant peut :
La suppression se propage en cascade sur 6 tables de base de données dépendantes, dans des transactions validées, sans fonctionnalité native d'annulation.
Fichier : includes/class-appointment-model.php
Le contrôle de permissions et le gestionnaire opèrent sur des portées complètement différentes :
// Route registration
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' ),
),
) );
Vérification des permissions — valide la possession d'UN rendez-vous via id_token :
public function get_items_permissions_check( $request ) {
// ...
if ( true === $this->id_token_permissions_check( $request ) ) {
return true; // grants access if caller proves ownership of one appointment
}
// ...
}
Gestionnaire — ignore le rendez-vous associé au jeton et agit à l'échelle du site :
public function purge_appointments( WP_REST_Request $request ) {
$params = $request->get_params();
// No customer_id or appointment_id scoping — deletes ALL matching appointments
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 );
// Cascade-deletes across 6 tables in committed transactions
}
L'id_token est un HMAC-MD5 dérivé de l'id et de date_created d'un seul rendez-vous. Posséder ce jeton prouve uniquement que l'appelant a réservé un rendez-vous précis — il ne confère aucun privilège à l'échelle du site, quel qu'il soit.
1. Attacker visits the booking page and books any free appointment
→ receives confirmation email containing: appointment_id + id_token
2. GET /wp-json/ssa/v1/appointments/purge
?id=<appointment_id>
&token=<id_token>
&purge_past_appointments=true
3. Permission check passes (valid token for attacker's own appointment)
4. Handler selects ALL past appointments site-wide → returns PII in response
→ permanently deletes them across 6 tables (on premium editions)
Le PoC sera publié le 2026-08-05 après l'embargo de divulgation coordonnée.
Consultez le répertoire poc/ après la date de l'embargo.
| Scénario | Résultat |
|---|---|
| Divulgation de données | Noms, e-mails, numéros de téléphone et détails des rendez-vous de tous les clients |
| Suppression massive (premium) | Tous les rendez-vous passés ou futurs définitivement détruits sur 6 tables |
| Aucune possibilité de récupération | Nécessite la restauration complète d'une sauvegarde de la base de données |
| Date | Événement |
|---|---|
| 2026-07-10 | Vulnérabilité découverte |
| 2026-07-10 | Soumise à WPScan |
| 2026-07-22 | CVE-2026-16540 attribuée |
| 2026-07-22 | Divulgation publique sur WPScan |
| 2026-08-05 | PoC publié |