# Un scanner de vulnérabilités a raté une faille métier : les limites de l’auto

> WPScan et Patchstack n'ont rien signalé sur cette extension maison. Une faille de logique métier s'y trouvait pourtant, invisible pour l'automatisation.

- Auteur : Clément Hadrot
- Publié le : 2024-01-08
- Mis à jour le : 2024-01-08
- Catégorie : Sécurité
- URL : https://wpmoderne.dev.wordpress-developpement.fr/securite/scanner-vulnerabilites-rate-faille-logique-metier/

## L’essentiel

- Deux scanners différents, zéro alerte
- La faille résidait dans l'enchaînement des vérifications
- L'audit manuel reste irremplaçable sur le code maison

Le site d'un client du secteur de la formation professionnelle proposait un configurateur de parcours pédagogique, développé sur mesure : l'utilisateur choisissait des modules, l'extension calculait un tarif, puis générait un devis PDF téléchargeable. Avant la mise en production d'une nouvelle version, deux passes automatisées avaient été lancées : un scan WPScan complet et une analyse Patchstack sur le code de l'extension. Les deux sont revenus verts, aucune vulnérabilité détectée.

Un audit manuel, demandé en complément parce que le client gérait des données de facturation sensibles, a mis au jour une faille bien réelle en moins d'une heure de lecture de code : un utilisateur pouvait obtenir un devis à un tarif déjà remisé, réservé aux comptes « entreprise », simplement en modifiant un paramètre d'URL, sans jamais déclencher la moindre alerte des outils automatisés qui avaient pourtant tourné dessus.

## Ce que WPScan et Patchstack savent chercher

WPScan fonctionne sur une base de données de vulnérabilités connues et publiées : il compare les versions de WordPress, des thèmes et des extensions installées à une liste de CVE répertoriées. Sur du code maison, jamais publié ni référencé nulle part, WPScan n'a tout simplement rien à comparer : il ne peut signaler que ce qui a déjà été découvert et documenté ailleurs par quelqu'un d'autre.

Patchstack va plus loin en proposant, sur son offre payante, une analyse statique du code à la recherche de motifs dangereux : appels à `eval`, requêtes SQL non préparées, sorties non échappées. C'est un travail précieux, mais qui reste circonscrit à des motifs de code identifiables ligne par ligne. Une analyse statique ne simule pas un parcours utilisateur complet, elle ne sait pas reconstituer qu'un paramètre A, combiné à l'absence d'un contrôle B, produit un résultat métier incohérent C.

## La faille telle qu'elle apparaissait dans le code

> L'essentiel à retenir : Deux scanners différents, zéro alerte ; La faille résidait dans l'enchaînement des vérifications ; L'audit manuel reste irremplaçable sur le code maison

Le configurateur exposait un shortcode qui affichait le formulaire de sélection de modules, et une action AJAX qui calculait le tarif côté serveur en fonction du profil de l'utilisateur connecté. Le code de calcul ressemblait à ceci :

```
add_action( 'wp_ajax_calculer_devis', 'formation_calculer_devis' );

function formation_calculer_devis() {
    $modules = array_map( 'intval', $_POST['modules'] );
    $remise  = isset( $_POST['code_remise'] ) ? sanitize_text_field( $_POST['code_remise'] ) : '';

    $total = formation_prix_modules( $modules );

    if ( 'ENTREPRISE2024' === $remise ) {
        $total = $total * 0.8;
    }

    wp_send_json_success( array( 'total' => $total ) );
}
```

Isolément, ce code ne présente aucun défaut technique évident : les entrées sont bien passées dans `intval` et `sanitize_text_field`, la requête SQL sous-jacente utilise `wpdb::prepare`. C'est précisément pour cette raison qu'aucun scanner ne l'a signalé : rien n'y ressemble à une injection, une XSS ou un appel dangereux. Le problème est ailleurs, dans la logique métier elle-même : le code de remise `ENTREPRISE2024` était censé n'être communiqué qu'aux clients ayant signé un contrat entreprise, mais rien dans le code ne vérifiait que l'utilisateur connecté appartenait réellement à cette catégorie. Le code de remise, une simple chaîne de caractères, avait fini par circuler par bouche-à-oreille entre stagiaires.

## Pourquoi l'automatisation ne pouvait pas le voir

Pour détecter cette faille automatiquement, un outil aurait dû savoir, sans qu'on le lui dise, que `ENTREPRISE2024` est censé être réservé à une catégorie d'utilisateurs, que cette catégorie se détermine par un champ métier précis (un statut de compte, une méta-donnée), et que son absence de vérification dans ce contexte constitue une faille. Aucune de ces informations n'existe dans une base de vulnérabilités connues, ni ne se déduit d'un motif de code générique. C'est une connaissance du métier du client, pas du code.

Ce constat ne remet pas en cause l'utilité de WPScan ou Patchstack, qui restent indispensables pour couvrir la surface la plus large possible à moindre coût : failles connues sur des extensions tierces, versions obsolètes, motifs de code dangereux répertoriés. Mais ils couvrent une catégorie de risques bien précise, et leur silence ne doit jamais être interprété comme un blanc-seing sur le code métier maison.

## Ce qu'un audit manuel apporte en plus

La méthode qui a permis de trouver la faille tenait en une question simple, posée en lisant le code fonction par fonction : « qu'est-ce qui empêche un utilisateur quelconque d'obtenir ce résultat réservé ? ». Concrètement, l'audit a suivi cette démarche :

- Repérer chaque avantage métier accordé conditionnellement (remise, accès, statut) dans le code.
- Pour chacun, identifier la condition censée le déclencher.
- Vérifier que cette condition est bien évaluée côté serveur, à partir d'une donnée que l'utilisateur ne contrôle pas directement.
- Tenter de contourner la condition en modifiant les paramètres envoyés, exactement comme le ferait un utilisateur curieux.

Le correctif a consisté à remplacer la vérification d'une chaîne de caractères par une vérification d'un statut réel, stocké côté utilisateur et non modifiable par le client :

```
$est_entreprise = get_user_meta( get_current_user_id(), 'statut_contrat', true ) === 'entreprise';

if ( $est_entreprise ) {
    $total = $total * 0.8;
}
```

> Un scanner vérifie que le code ne fait rien de mal connu. Un audit manuel vérifie que le code fait bien ce qu'il est censé faire, et rien de plus.

## Ce que ça révèle sur les limites de l'automatisation

Cet épisode illustre une distinction utile à garder en tête pour tout projet WordPress reposant sur du développement sur mesure : les outils automatisés sécurisent efficacement le socle commun, cœur, thèmes et extensions publiées, parce qu'ils s'appuient sur une base de connaissance partagée par toute la communauté. Le code métier propre à un client, lui, ne bénéficie d'aucune base de comparaison, et sa sécurité repose entièrement sur la rigueur de la revue humaine au moment où il est écrit. Sur ce projet, la règle appliquée depuis est simple : toute fonctionnalité qui accorde un avantage conditionnel (tarif, accès, quantité) fait l'objet d'une checklist de revue dédiée, indépendante des scanners automatisés lancés par ailleurs.
