Le dossier wp-content/uploads a une particularité que beaucoup de propriétaires de sites oublient : c’est le seul endroit du serveur où des fichiers arrivent en continu depuis l’extérieur, via les formulaires de médiathèque, les extensions d’import ou parfois des formulaires de contact mal sécurisés. Si un attaquant parvient, par une faille quelconque, à y déposer un fichier .php, et que le serveur accepte de l’exécuter, la partie est perdue : il dispose d’un accès direct à l’exécution de code arbitraire.
La bonne nouvelle, c’est que cette attaque classique se neutralise entièrement au niveau du serveur web, indépendamment de la faille d’origine qui a permis le dépôt du fichier. Une seule règle de configuration, posée une fois pour toutes, ferme cette porte pour n’importe quelle extension présente ou future sur le site.
Pourquoi ce dossier précisément
WordPress n’a normalement aucune raison d’exécuter du PHP situé dans wp-content/uploads : ce répertoire est censé ne contenir que des images, documents et autres médias, jamais de code applicatif. Autoriser malgré tout ce dossier à exécuter du PHP par défaut, comme le font de nombreuses configurations serveur sorties d’usine, revient à laisser une porte ouverte qui ne sert jamais en usage normal, mais qui devient critique le jour où un attaquant trouve un moyen d’y déposer un script, que ce soit via une faille d’upload dans une extension, une vulnérabilité d’import de fichiers ou un accès FTP compromis.
La règle sous nginx
Sous nginx, il suffit d’ajouter un bloc de localisation qui intercepte toute tentative d’exécution de PHP dans ce dossier avant qu’elle n’atteigne le gestionnaire FastCGI habituel :
location ~* /wp-content/uploads/.*\.php$ {
deny all;
}
Ce bloc doit être placé avant la configuration générale qui transmet les fichiers .php à PHP-FPM, afin que nginx l’évalue en priorité. Un rechargement de la configuration suffit à l’activer :
nginx -t && systemctl reload nginx

La règle sous Apache
Sous Apache, la même protection passe par un fichier .htaccess déposé directement dans wp-content/uploads, ou par un bloc équivalent dans la configuration principale du site :
<FilesMatch "\.php$">
Require all denied
</FilesMatch>
Sur les versions d’Apache antérieures à 2.4, la syntaxe diffère légèrement et utilise Deny from all à la place de Require all denied. Il convient de vérifier la version active avec apache2 -v avant de choisir la syntaxe adaptée.
Vérifier que la règle fonctionne réellement
Une règle mal placée ou mal interprétée peut donner une fausse impression de sécurité. La méthode la plus fiable pour vérifier consiste à déposer volontairement, en environnement de test, un fichier PHP inoffensif :
echo '<?php echo "test-execution"; ?>' > wp-content/uploads/test.php
Puis à ouvrir https://votre-site.test/wp-content/uploads/test.php dans un navigateur. Deux résultats possibles :
- Le navigateur affiche une erreur 403 ou le contenu brut du fichier sans exécution : la protection fonctionne.
- Le texte « test-execution » s’affiche : le fichier a bien été exécuté par PHP, la règle n’est pas active et mérite d’être corrigée en urgence.
Il ne faut évidemment pas oublier de supprimer ce fichier test une fois la vérification effectuée.
Ce que cette règle ne remplace pas
Bloquer l’exécution de PHP dans uploads ne dispense pas de valider correctement le type et le contenu des fichiers envoyés côté applicatif, ni de maintenir les extensions à jour. C’est une protection en profondeur : même si une faille d’upload venait à exister dans une extension, le pire scénario — l’exécution du fichier déposé — resterait impossible. C’est précisément l’intérêt d’une défense en couches : chaque niveau limite les dégâts si le précédent est franchi.
Sur tous les sites que nous provisionnons, cette règle fait partie du modèle serveur de base, au même titre que la configuration TLS : elle ne coûte rien en fonctionnement normal et évite un scénario catastrophe.
En résumé
Interdire l’exécution de PHP dans wp-content/uploads est l’une des mesures les plus rentables qui soient : une poignée de lignes de configuration serveur, aucun impact sur le fonctionnement normal du site, et une voie d’attaque entière neutralisée d’un coup, quelle que soit l’extension à l’origine d’une éventuelle faille future.