Quand on parle de sécurité WordPress, on imagine souvent des injections SQL ou des failles dans des plugins “exotiques”. Pourtant, il existe un autre scénario plus silencieux et parfois plus difficile à diagnostiquer: le directory traversal, ou parcours de répertoires. Le principe est simple, l’impact peut être immense. Une application mal protégée peut laisser un attaquant lire des fichiers en dehors du dossier prévu, voire s’appuyer sur ces fichiers pour progresser.
Je l’ai vu plusieurs fois en intervention, et presque toujours avec le même schéma: une route ou une fonctionnalité qui “charge un fichier” à partir d’un paramètre d’URL, une validation absente ou superficielle, puis un attaquant qui remonte dans l’arborescence avec ../ ou des variantes. Parfois la découverte se fait au hasard via des logs, parfois parce que quelqu’un a déjà “joué” avec l’URL et déclenché une erreur révélatrice.
Ce billet détaille comment fonctionne le directory traversal côté WordPress et autour, quels endroits sont les plus exposés, et surtout quoi faire concrètement pour renforcer la sécurité WordPress, sans casser des plugins ou compliquer inutilement la maintenance.
Comprendre le directory traversal, sans le mystifier
Le directory traversal consiste à forcer le serveur à accéder à un chemin de fichier différent de celui que l’application a prévu. L’attaque vise l’écart entre:
- ce que le développeur croit recevoir (un nom de fichier “innocent” ou une valeur attendue), et ce que le serveur reçoit réellement (un chemin interprété par le système de fichiers).
Sur un serveur Linux, le chemin relatif ../ signifie “remonte d’un niveau”. En combinant des segments, un attaquant peut tenter de construire un chemin qui sort du répertoire cible. Selon la manière dont le site est codé, cela peut mener à la lecture de fichiers sensibles comme des fichiers de configuration, des logs, ou du code source.
Deux points rendent cette classe de vulnérabilités particulièrement piégeuse:
Elle ne dépend pas forcément d’une injection “active”. On peut exfiltrer des données sans écrire quoi que ce soit. Les protections partielles ne suffisent pas. Une regex qui “interdit ../” peut être contournée par des encodages, des variantes de séparateurs, ou des erreurs d’interprétation.Dans WordPress, le cœur du système est plutôt robuste quand on reste dans les parcours standards. Là où ça se complique, c’est quand un plugin ou un thème ouvre un accès à un système de fichiers via un paramètre: téléchargement de fichier, lecture d’un gabarit, export/import, affichage d’un modèle, import d’un log, ou même gestion d’images “à la volée” dans certaines extensions.
Où se cache le risque dans l’écosystème WordPress
WordPress est un framework de CMS, pas une application monolithique. Le directory traversal apparaît rarement “dans WordPress” au sens strict, plus souvent dans:
- un plugin qui lit un fichier depuis une variable, un thème qui charge une ressource en construisant un chemin, un script custom dans wp-content ou via un hook, un endpoint REST mal sécurisé, une fonctionnalité AJAX qui retourne des contenus de fichiers.
Il faut penser “données externes vers chemin système”. La question à se poser est très pragmatique: “Quel endpoint accepte un paramètre et ensuite utilise ce paramètre pour construire un chemin sur disque ?”
Un exemple typique (conceptuel) ressemble à ça: l’application reçoit un paramètre file=..., puis fait quelque chose du genre readfile($baseDir.'/'.$file). Même si $file est censé être un nom de fichier, la validation peut être insuffisante. Si l’attaquant passe ../../wp-config.php, le chemin final pointe ailleurs.

Dans un site WordPress, l’ampleur du problème dépend aussi du contexte serveur:
- si l’utilisateur système du serveur web peut lire certains fichiers, si les fichiers sensibles sont accessibles depuis le même compte, si la configuration PHP limite la lecture (souvent non), et si le serveur bloque certains chemins.
Mais même quand l’impact direct est limité, une fuite de chemins, d’erreurs ou d’extraits de fichiers peut donner des informations utiles à la suite (structure du site, présence de fichiers, versions, chemins absolus).
Les symptômes: comment le directory traversal se manifeste en production
Le directory traversal n’a pas toujours une “explosion” visible. Il peut donner des comportements subtils:
- des erreurs 404 ou 500 quand un chemin invalide est tenté, des réponses contenant des morceaux de fichiers (parfois partiels), des différences de taille de réponse pour des variations d’URL, des logs serveur montrant des tentatives répétées de type traversal.
Dans mes expériences, on voit souvent des requêtes qui tentent plusieurs variantes. Parfois l’attaquant se contente de ../ simple, parfois il teste des encodages comme %2e%2e/ (le point “décodé” sur le serveur), ou des répétitions.
Un indice précieux est la cohérence entre le paramètre et la réponse. Si changer file= change aussi la taille ou le contenu renvoyé de façon “trop précise”, c’est un drapeau rouge.
Pourquoi les “filtres simples” échouent souvent
Une erreur fréquente consiste à faire un nettoyage naïf du paramètre. Par exemple: “je supprime les caractères .” ou “je bloque la chaîne ../”. Le problème est que l’interprétation du chemin peut se produire après décodage, normalisation, ou dans une autre partie du code.
Les contournements courants passent par:
- des encodages URL multiples, des séquences similaires comme ..%2f, l’utilisation de séparateurs alternatifs selon le système ou la normalisation, la présence de caractères Unicode ou de variantes qui ne sont pas traités pareil.
Sans faire une liste exhaustive, le message est clair: valider “au feeling” est rarement assez. Ce qui fonctionne vraiment en pratique, c’est une stratégie de défense basée sur le chemin canonique final et le confinement à un répertoire autorisé.
La stratégie qui tient: “confinement” au répertoire autorisé
Le principe de base est toujours le même, quel que soit le langage ou l’environnement: on ne doit jamais utiliser un paramètre utilisateur comme chemin “relatif” libre. Si on doit accéder à un fichier, on doit construire un chemin de manière contrôlée, puis vérifier que le chemin final reste dans un répertoire attendu.
Concrètement, ça veut dire deux actions:
Construire le chemin depuis un point d’ancrage fixe (par exemple un dossier de stockage autorisé). Calculer le chemin final normalisé et vérifier qu’il commence bien par le préfixe autorisé.En PHP, le concept s’exprime souvent via la normalisation (realpath) ou des opérations équivalentes. Le piège, c’est que realpath renvoie false si le chemin n’existe pas. Selon le cas d’usage (par exemple, proposer un téléchargement d’un fichier qui doit exister), on peut traiter ce cas explicitement. L’idée n’est pas de “rendre tout possible”, mais de rejeter ce qui ne matche pas les contraintes.
Cette approche est aussi plus robuste contre les encodages, parce que la comparaison s’effectue sur le chemin final interprété, pas sur une chaîne “brute” reçue par l’application.
Ce que vous pouvez faire sur un site WordPress pour réduire le risque
La meilleure réponse dépend de votre situation: site multi-plugins, code custom, budget d’audit, niveau de contrôle sur le serveur, et contrainte de compatibilité. Je vous propose une démarche pragmatique, orientée renforcement de sécurité WordPress et réduction de surface.
1) Cartographier les points d’accès aux fichiers
Commencez par identifier les endroits où le code manipule un “paramètre de fichier”. Dans un projet WordPress classique, cela se traduit souvent par:
- des appels à des fonctions lecture de fichiers (file_get_contents, readfile, fopen, include, require) combinés à des variables issues de requêtes, des endpoints REST ou AJAX qui “retournent un contenu de fichier”, des pages d’administration qui permettent de sélectionner un fichier ou un dossier.
Sur un site qui tourne déjà, je préfère travailler à partir de preuves. Regardez les logs applicatifs et serveur, puis ciblez l’endpoint ou le plugin qui prend ces paramètres. Si vous n’avez pas de logs, activez-en une couche minimale (sans exposer de données sensibles) et testez en environnement contrôlé.
2) Mettre des garde-fous côté application, pas uniquement via filtrage
Le filtrage en entrée peut aider à réduire les tentatives opportunistes, mais ce n’est pas une barrière de sécurité complète. La vraie protection doit être dans la construction du chemin et la vérification du confinement.
Si vous maintenez un plugin maison, appliquez cette règle partout où un chemin est construit. Si vous dépendez d’un plugin tiers, vous avez parfois le choix entre:
- mettre à jour le plugin si le correctif est disponible, isoler la fonctionnalité, ou appliquer un remplacement supervisé via un hook, au prix d’efforts supplémentaires.
Dans la pratique, dès que j’ai un doute sur un plugin, je préfère une mise à jour ou un contournement. Contourner “à la main” une validation dans un endroit fragile est un travail qui doit être maintenu, et ça finit souvent par casser au prochain changement.
3) Appliquer des règles de confinement au niveau fichier et au niveau serveur
Même si votre application est corrigée, une couche serveur peut réduire l’impact en cas de régression.
Au niveau serveur, les configurations dépendent fortement de l’hébergement. Je ne vais pas vous donner une recette universelle, mais je retiens trois leviers qui reviennent:
- limiter les permissions du compte système utilisé par PHP, empêcher la lecture directe de certains fichiers via le web (configuration Apache ou Nginx), s’assurer que l’application n’a pas de droits inutiles.
Si votre serveur web tourne avec un compte qui a accès à des fichiers sensibles, un traversal réussit a plus de chances d’aboutir. À l’inverse, si les permissions sont strictes, le traversal devient souvent une fuite de chemins, pas une exfiltration de données.
Exemple concret: construire un chemin sûr (et éviter les pièges)
Imaginons un endpoint qui permet de télécharger un fichier depuis un répertoire de “documents” dans wp-content/uploads/documents. Le développeur veut accepter un identifiant, par exemple doc-123.pdf.
La bonne approche consiste à considérer que l’entrée utilisateur n’est pas un chemin, mais une clé logique. Ensuite, vous mappez la clé vers un nom de fichier attendu selon une liste ou une règle contrôlée. Par exemple, vous autorisez seulement certains patterns stricts:
- doc-id.pdf où id est numérique, et vous rejetez toute autre chose.
Ensuite, vous construisez le chemin final à partir du dossier de base. Enfin, vous vérifiez que le chemin final appartient bien à ce dossier.
Deux décisions importent:
- Le dossier de base doit être absolu, fixé dans la configuration, pas calculé depuis l’entrée. La vérification doit utiliser le chemin normalisé final, pas uniquement un test “contient ../”.
C’est le type de correction qui résiste à des entrées encodées et à des variantes de traversal.
Petite checklist de triage (rapide mais efficace)
Quand vous suspectez un directory traversal sur un site WordPress, commencez par vérifier ces points:
- Le paramètre suspect est-il utilisé directement dans une opération de chemin (include, readfile, fopen, require) ? Le code normalise-t-il le chemin final avant comparaison, ou teste-t-il une chaîne d’entrée brute ? Le chemin final est-il “confiné” à un dossier autorisé ? Le plugin ou le thème a-t-il une mise à jour récente qui mentionne la sécurité ? Les logs montrent-ils des tentatives répétées cohérentes avec traversal et une réponse différente à chaque essai ?
Cette checklist ne remplace pas un audit, mais elle oriente vite.
Vérifier et corriger sans casser le site: l’enjeu de la compatibilité
Un correctif “propre” peut aussi créer un problème d’exploitation. Par exemple:
- un plugin utilisait des chemins relatifs “malgré tout”, ou des fichiers historiques se trouvaient dans un dossier non standard.
Si vous imposez un confinement strict basé sur un dossier unique, vous risquez de casser l’accès à des fichiers qui étaient auparavant accessibles. D’où l’importance de définir le périmètre fonctionnel avant la correction. Dans un audit, je demande souvent: “Quels fichiers doivent être accessibles réellement ?” Si la réponse est floue, je préfère d’abord clarifier via tests et vérification du comportement actuel.
Autre piège: autoriser des chemins “propres” mais pas forcément “attendus”. Par exemple, accepter “../../..” serait évidemment dangereux. Mais même accepter “../uploads/x.pdf” dans un mauvais système de mapping peut ouvrir une nouvelle voie. La sécurité, ici, est une question de design, pas seulement de regex.
Durcir WordPress et ses couches périphériques (sans magie)
Renforcer sécurité WordPress, c’est rarement une action unique. Pour le directory traversal, je recommande une approche en couches, avec un équilibre entre effort et risque.
Actions côté application et déploiement
Voici une séquence que j’utilise souvent quand j’ai accès au code et que le site est en production mais encore “tenable”:
Identifier le plugin, thème, ou endpoint qui traite le paramètre de chemin, à partir des logs et de l’inspection. Mettre à jour ce composant si un correctif existe, sinon isoler la fonctionnalité temporairement. Remplacer la logique de construction de chemin par une logique “clé vers fichier” ou un confinement contrôlé. Tester avec des entrées de type traversal variées, y compris encodées, dans un environnement proche de la production.Cette séquence permet d’éviter de “corriger trop tard”. La phase de test n’est pas cosmétique, elle réduit les mauvaises surprises.
Actions côté configuration serveur
Au niveau serveur, l’objectif est simple: limiter ce qu’un attaquant peut lire ou exécuter si l’application fait une erreur. Selon votre stack, cela peut inclure:
- désactiver les expositions directes de répertoires, configurer le serveur pour refuser les accès à certains fichiers sensible, ajuster les permissions du compte PHP-FPM ou Apache.
Vous n’avez pas besoin de tout verrouiller à la première passe. Mais si vous ne pouvez pas auditer tout le code, renforcer l’environnement devient un filet de sécurité utile.
Focus sur les endpoints REST et AJAX: le terrain où tout se joue
Beaucoup de scans automatisés ciblent des endpoints parce qu’ils répondent souvent de manière homogène. Un endpoint REST peut sembler “inoffensif” parce qu’il ne sert que des données JSON. Pourtant, si un paramètre commande l’accès à un fichier, vous avez un canal pour le traversal.
Deux cas reviennent:
- L’endpoint renvoie le contenu d’un fichier ou un extrait. L’endpoint déclenche une opération qui dépend d’un chemin, même si ce n’est pas une lecture directe.
Dans les deux cas, le correctif doit vérifier le confinement au moment où l’application choisit un fichier. Le fait que la réponse soit du JSON n’annule pas le risque.
Sur un site WordPress, je conseille aussi de vérifier les permissions. Certains endpoints acceptent des paramètres même sans authentification ou avec des rôles trop permissifs. Un traversal exploité par un utilisateur authentifié limité est déjà grave, mais un accès public rend le problème plus urgent.
Comment tester de façon responsable, sans “bricoler” en aveugle
Tester la sécurité d’un site en production est délicat. Les requêtes de traversal peuvent générer des erreurs serveur, consommer des ressources, ou déclencher des règles de sécurité externes. La démarche que je privilégie:
- tester sur une copie de l’environnement quand c’est possible, limiter le volume de requêtes, surveiller les logs et l’état du serveur, et conserver un registre des tests pour comparer le avant/après.
Je n’encourage pas à lancer des scans agressifs. Un bon test ne consiste pas à “voir jusqu’où ça va”, mais à vérifier que votre confinement bloque l’accès hors périmètre. Si votre correctif fonctionne, les réponses devraient devenir cohérentes et refuser les chemins non autorisés.
Quand le problème vient d’un plugin tiers: quoi faire concrètement
Le cas le plus fréquent en maintenance, c’est la dépendance à un plugin. Vous n’écrivez pas le code, vous ne lisez pas la validation, vous subissez le risque.
Voici comment trier sans perdre du temps:
- Si le plugin a une mise à jour de sécurité, faites-la. C’est souvent la meilleure option. Si vous n’avez pas d’update, essayez d’identifier la fonctionnalité à l’origine. Parfois une option dans le plugin déclenche l’accès aux fichiers, et la désactivation suffit en attendant. Si vous devez garder le plugin, vous pouvez parfois corriger via un correctif applicatif supervisé, mais cela demande de la vigilance et des tests à chaque mise à jour.
Ce que je déconseille, c’est de patcher au hasard. Une regex ajoutée “à l’arrache” peut réduire un pattern précis, mais rester vulnérable à une variante encodée.
Mesurer l’amélioration: ce qui prouve que la défense marche
Après correctif, je cherche des preuves simples et observables:
- Les tentatives de traversal doivent échouer sans que l’application révèle de chemins internes ou d’erreurs détaillées. Le comportement doit être stable. Une fois que le chemin final est rejeté, toutes les variantes de traversal pertinentes devraient être refusées de façon cohérente. Les logs devraient montrer moins de répétitions exploitables, ou des tentatives sans effet.
Côté sécurité, la cohérence est un indicateur fort. Si certaines variantes passent, cela veut dire que votre validation n’est pas fondée sur la normalisation du chemin final.
Points d’attention spécifiques aux fichiers sensibles
Lorsqu’un traversal est corrigé, il peut rester une seconde couche d’outils. Par exemple, si le plugin exposait des fichiers par une route de téléchargement, vérifiez:
- que seuls les fichiers réellement nécessaires sont accessibles, que les types MIME et l’en-tête de réponse n’encouragent pas des scripts côté client (selon le navigateur), que les noms de fichiers ne révèlent pas l’arborescence ou les chemins absolus.
Et si l’attaque a déjà été exploitée, pensez aussi à l’impact potentiel. Même une fuite “lecture seule” peut demander une revue plus large: rotation de secrets si une configuration a été https://gardewp.fr/securite-wordpress/ exposée, vérification d’intégrité des fichiers si un code a pu être téléchargé ou modifié via d’autres vulnérabilités.
Réduire la surface dans WordPress au quotidien
Au-delà du directory traversal, l’hygiène globale aide énormément. Des gestes simples réduisent l’exposition à ce type de vulnérabilité:
- garder WordPress, thèmes et plugins à jour, supprimer ou mettre en pause les plugins rarement utilisés, limiter l’accès administrateur, vérifier les permissions des rôles, surveiller les logs après déploiement.
Je sais que ces recommandations sonnent “classiques”, mais sur le terrain, ce sont elles qui font la différence entre une vulnérabilité détectée tôt et une exploitation qui laisse des traces difficiles à effacer.
Le directory traversal est particulièrement sournois quand il arrive dans un plugin oublié. C’est souvent là que je vois les problèmes les plus anciens: une fonctionnalité qui servait une fois, puis restée en place pendant des mois, avec un paramètre jamais durci.
Checklist finale avant de dire “c’est bon”
Vous voulez une règle pratique pour valider votre correction. Si vous faites une seule vérification de haut niveau, faites celle-ci: l’application ne doit jamais permettre à un utilisateur de transformer une chaîne en chemin arbitraire sur le système de fichiers.
Avant de fermer le dossier, je recommande de vérifier ces éléments, dans le même esprit que la checklist précédente:
- Le chemin final est-il comparé à un dossier autorisé, après normalisation ? Les entrées encodées et les variantes traversal sont-elles refusées ? L’erreur retournée ne révèle-t-elle pas de détails excessifs (chemins absolus, stack trace) ? Les permissions serveur limitent-elles l’impact potentiel ? Le correctif est-il couvert par un test ou au minimum par un scénario de validation manuel reproductible ?
Si ces points tiennent, vous avez un vrai gain de sécurité, pas une correction superficielle.
Si vous voulez, donnez-moi le nom du plugin ou le type d’endpoint que vous suspectez, et je peux vous proposer une stratégie de validation plus ciblée (périmètre exact des chemins, tests à effectuer, et formulation d’une correction adaptée à votre cas).