Une agence de communication nous confie l’analyse d’une extension d’import de contenu développée en interne, destinée à automatiser la migration de contenus entre plusieurs sites WordPress d’un même groupe de marques. L’extension accepte, comme l’importeur natif de WordPress, un fichier au format WXR (WordPress eXtended RSS), une extension du format RSS qui embarque l’ensemble des articles, pages, médias et métadonnées d’un site dans un unique document XML structuré.
La question posée par l’agence est précise : ce format étant du XML, et le XML étant historiquement associé aux attaques par entité externe (XXE), l’extension maison est-elle exposée à ce risque, et que fait WordPress nativement pour s’en protéger ?
Rappel du mécanisme d’une attaque XXE
Le format XML permet de définir des entités personnalisées dans un document, un mécanisme initialement prévu pour éviter de répéter du contenu (à la manière d’une variable). Une entité externe pousse ce mécanisme plus loin en permettant de référencer le contenu d’une ressource externe — un fichier local du serveur, voire une URL distante — directement depuis l’intérieur du document XML, qui sera alors inclus lors du traitement du fichier par le parseur :
<?xml version="1.0"?>
<!DOCTYPE rss [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<rss>
<channel>
<item>
<title>&xxe;</title>
</item>
</channel>
</rss>
Si le parseur XML utilisé pour lire ce document résout effectivement cette entité externe, le contenu du fichier système référencé (ici /etc/passwd, un exemple classique de démonstration) se retrouve inséré dans la donnée traitée, exposant potentiellement des fichiers sensibles du serveur à quiconque peut consulter le résultat de l’import. Selon la configuration, une attaque XXE peut aussi servir à sonder le réseau interne du serveur (SSRF via une URL au lieu d’un fichier local) ou, dans des cas plus avancés, contribuer à un déni de service par expansion d’entités récursives.
Ce que fait PHP par défaut, et pourquoi la version compte

En PHP, le traitement XML repose généralement sur l’extension libxml, utilisée en interne par les fonctions SimpleXML, DOMDocument et XMLReader (cette dernière étant celle utilisée par l’importeur WordPress natif pour traiter les fichiers WXR, précisément parce qu’elle permet un traitement en flux, plus économe en mémoire pour de gros fichiers d’export). Historiquement, avant PHP 8.0, le chargement des entités externes n’était pas désactivé par défaut par libxml : il fallait explicitement appeler libxml_disable_entity_loader( true ) pour s’en protéger, une étape qu’un développeur non sensibilisé au risque XXE pouvait facilement omettre.
Depuis PHP 8.0, la version de libxml intégrée protège par défaut contre le chargement des entités externes, indépendamment de tout appel explicite à cette fonction (elle-même dépréciée depuis cette version, précisément parce qu’elle n’a plus lieu d’être appelée). Un site tournant sur PHP 8.0 ou supérieur bénéficie donc de cette protection au niveau du moteur PHP lui-même, sans configuration additionnelle du côté de l’extension d’import.
Ce que WordPress fait spécifiquement pour son importeur natif
L’importeur WXR natif de WordPress applique, en complément de la protection par défaut de PHP moderne, des vérifications supplémentaires propres à son propre traitement : il valide la structure attendue du document avant traitement, encadre la lecture avec XMLReader plutôt qu’un chargement complet en mémoire par DOMDocument (ce qui limite par ailleurs l’impact d’une éventuelle attaque par expansion d’entités, dite « bombe XML »), et ne traite que les éléments explicitement attendus du schéma WXR, ignorant le reste du document.
Vérifier concrètement une extension d’import maison
Pour l’extension de cette agence, la vérification a porté sur trois points précis, indépendamment de la version de PHP utilisée en production (une bonne pratique reste de ne jamais reposer une protection de sécurité uniquement sur une version de dépendance externe, qui peut évoluer sans que le code applicatif ne le sache) :
// Vérification explicite, peu coûteuse et indépendante de la version de PHP,
// à conserver même sur un environnement déjà protégé par défaut.
function moncpt_charger_wxr_en_securite( $chemin_fichier ) {
$etat_precedent = libxml_disable_entity_loader( true );
$document = new DOMDocument();
$document->load( $chemin_fichier, LIBXML_NONET ); // interdit aussi les accès réseau
libxml_disable_entity_loader( $etat_precedent );
return $document;
}
La constante LIBXML_NONET, passée aux fonctions de chargement, interdit également toute résolution d’entité par accès réseau, une protection complémentaire utile même quand le chargement d’entités externes locales est déjà neutralisé par ailleurs — une défense en profondeur qui ne coûte rien et qui protège aussi les environnements où la version de PHP ne serait pas celle attendue.
Le test de validation a consisté à soumettre volontairement à l’extension un fichier WXR modifié, contenant une entité externe pointant vers un fichier local du serveur de test, et à vérifier que le contenu de ce fichier n’apparaissait jamais dans le résultat de l’import, quelle que soit la version de PHP utilisée pour le test.
Recommandation finale pour l’agence
Conclusion transmise : l’extension maison, une fois la vérification explicite ajoutée en complément de la protection native de PHP 8, ne présentait plus de risque XXE identifiable. La recommandation a porté également sur la mise à jour de la version de PHP sur l’ensemble des sites du groupe encore en PHP 7.4, dont le support de sécurité officiel touchait par ailleurs à sa fin, pour bénéficier structurellement de cette protection par défaut plutôt que de dépendre uniquement d’un correctif applicatif.
Sur ce projet, la règle retenue est devenue : toute manipulation de XML dans une extension, quel que soit son usage prévu, passe systématiquement par une vérification explicite de la désactivation des entités externes, sans jamais supposer que l’environnement d’exécution s’en charge tout seul.
Pour aller plus loin
Cet article ne détaille pas le format WXR lui-même (sa structure, ses éléments, ses limites pour la migration de contenu complexe), un sujet distinct qui mériterait son propre traitement. Il se concentre sur le risque de sécurité spécifique que ce format, en tant que dialecte XML, porte intrinsèquement, et sur la façon de vérifier qu’il est correctement neutralisé avant tout traitement d’un fichier dont l’origine ne peut être garantie à cent pour cent.