# « wp cron event run » manuel : un événement planifié détourné

> Un lien discret dans l'administration permettait de déclencher à volonté un traitement lourd, sans la moindre vérification de capacité.

- Auteur : Clément Hadrot
- Publié le : 2024-05-11
- Mis à jour le : 2024-05-11
- Catégorie : Sécurité
- URL : https://wpmoderne.dev.wordpress-developpement.fr/securite/wp-cron-event-run-evenement-detourne/

## L’essentiel

- Un déclenchement manuel d'événement doit vérifier une capacité, pas juste une connexion
- Un lien d'action directe expose la même surface qu'une route REST
- wp cron event run aide à reproduire le comportement sans attendre le planificateur

« Pourquoi ce traitement d'export s'exécute-t-il vingt-deux fois en une heure, alors qu'il est planifié une seule fois par jour ? » Cette question, posée par un développeur consultant les journaux applicatifs d'un site d'intranet associatif, a mené à la découverte d'un événement cron détournable par un utilisateur sans droit particulier.

Le site proposait, dans son tableau de bord d'administration, un bouton « Générer l'export maintenant », destiné à forcer manuellement l'exécution d'un événement normalement planifié une fois par jour via `wp_schedule_event()`. Ce bouton s'est révélé accessible à des comptes qui n'auraient jamais dû pouvoir le déclencher.

## Symptôme

Les journaux du serveur montraient des appels répétés à l'action `export_donnees_quotidien`, générant chacun un fichier volumineux et consommant plusieurs secondes de traitement CPU intensif. La fréquence de ces appels ne correspondait à aucune planification légitime, et leur horaire ne suivait pas non plus le déclenchement habituel du planificateur WordPress lié au trafic du site.

## Diagnostic

Le bouton du tableau de bord pointait vers une URL du type `admin.php?page=export&action;=lancer_maintenant`, traitée par un gestionnaire qui déclenchait directement l'action associée à l'événement cron :

```
add_action( 'admin_init', function () {
    if ( isset( $_GET['action'] ) && 'lancer_maintenant' === $_GET['action'] ) {
        do_action( 'export_donnees_quotidien' );
    }
} );
```

Ce code s'exécutait pour tout utilisateur connecté capable d'atteindre une page d'administration, sans distinction de rôle. Aucun appel à `current_user_can()` ni aucune vérification de nonce n'entourait le déclenchement. Reproduire le comportement en local, à l'aide de la commande `wp cron event run export_donnees_quotidien`, a confirmé que le traitement lui-même fonctionnait correctement : le défaut ne résidait pas dans la logique métier de l'export, mais uniquement dans son point de déclenchement manuel.

> L'essentiel à retenir : Un déclenchement manuel d'événement doit vérifier une capacité, pas juste une connexion ; Un lien d'action directe expose la même surface qu'une route REST ; wp cron event run aide à reproduire le comportement sans attendre le planificateur

## Correctif

La correction ajoute une vérification de capacité adaptée à l'action réellement sensible, accompagnée d'un nonce pour empêcher qu'un lien forgé ne déclenche l'action à l'insu d'un administrateur légitime naviguant sur le site.

```
add_action( 'admin_init', function () {
    if (
        isset( $_GET['action'], $_GET['_wpnonce'] )
        && 'lancer_maintenant' === $_GET['action']
        && current_user_can( 'manage_options' )
        && wp_verify_nonce( $_GET['_wpnonce'], 'lancer_export_maintenant' )
    ) {
        do_action( 'export_donnees_quotidien' );
    }
} );
```

Le lien du bouton a également été régénéré avec `wp_nonce_url()` pour intégrer ce nonce automatiquement, et la vérification de capacité a été alignée sur celle déjà utilisée pour accéder à la page d'administration elle-même, évitant toute incohérence entre les deux niveaux de contrôle.

## Prévention

Ce type de défaut se reproduit facilement dès qu'un bouton d'action directe est ajouté à une page d'administration existante, sous la pression d'un besoin ponctuel, sans repasser par la même rigueur qu'un formulaire classique. Trois réflexes limitent ce risque à l'avenir.

- Traiter tout déclenchement manuel d'un événement cron comme une action sensible à part entière, jamais comme un simple raccourci d'affichage.
- Systématiser l'usage de `wp cron event run` en environnement de test pour isoler la logique métier du point de déclenchement, avant toute mise en production.
- Revoir chaque bouton d'action directe d'une page d'administration lors des audits de sécurité périodiques, au même titre que les routes REST personnalisées.

> Repère retenu de ce diagnostic : un événement cron déclenché manuellement depuis l'administration reste une action, avec les mêmes exigences de contrôle qu'un formulaire de suppression ou de publication.

## En résumé

Le problème observé ne tenait ni à la configuration générale de WP-Cron ni à la fiabilité de sa planification, mais à un point de déclenchement manuel ajouté sans les mêmes garde-fous que le reste de l'interface d'administration. La commande `wp cron event run` s'est révélée précieuse pour isoler cette cause, en permettant de rejouer l'événement indépendamment du bouton défaillant.
