L'injection XML est la manipulation d'une entrée XML pour modifier la façon dont une application analyse ou interprète les données. Elle se produit lorsque des données contrôlées par l'utilisateur sont insérées dans un document XML sans validation appropriée, ce qui permet aux attaquants d'injecter des nœuds, des attributs, des entités ou des charges utiles qui modifient le flux de contrôle, contournent la logique ou déclenchent des comportements dangereux de l'analyseur. Dans les écosystèmes actuels, riches en API et axés sur l'intégration, l'injection XML reste une menace réelle que les équipes de sécurité ne peuvent ignorer.
Contrairement à la simple altération des entrées, l'injection XML exploite la puissance expressive du XML lui-même, ce qui a un impact sur les systèmes complexes, notamment SOAP, SAML, les appareils IoT, les intégrations d'entreprise et les systèmes financiers hérités.
Pourquoi l'injection XML est toujours d'actualité
Même si JSON domine les applications modernes, XML est profondément ancré dans les logiciels d'entreprise, les protocoles d'authentification et les intégrations dorsales. Les attaquants peuvent abuser des structures XML pour :
- Altérer la logique d'entreprise
- Injecter des nœuds non autorisés
- Manipuler les requêtes XPath
- Déclenchement d'une divulgation de fichiers de type XXE
- Interrompre la validation du schéma
- Provoquer un déni de service basé sur XML
La flexibilité du XML rend son utilisation abusive particulièrement puissante.
Exemple réel de CVE : CVE-2025-13526
CVE-2025-13526 démontre comment une simple mauvaise configuration de l'analyse XML peut conduire à la divulgation complète d'un fichier. Le système autorisait le téléchargement de fichiers de configuration XML, mais ne parvenait pas à désactiver la résolution d'entités externes.
Exemple de charge utile malveillante :
xml
<!DOCTYPE data [
]>
&xxe;
Le serveur a renvoyé le contenu de /etc/passwdqui montre comment l'injection de XML combinée à XXE peut exposer des fichiers critiques.
Surfaces d'attaque de l'injection XML
Les attaquants abusent :
- Injection de nœuds
- Injection d'attributs
- Manipulation de requêtes XPath
- Manipulation du schéma (XSD)
- Charges utiles XXE
- Extension d'entité pour DoS
- Contournement logique dans les flux de travail basés sur XML
Chaque catégorie a un impact sur une couche différente du système.
Exemples d'attaques (même quantité conservée)
- Manipulation de l'injection de nœuds
xml
ProduitA
Charge utile injectée :
pgsql
true
Le XML qui en résulte est structurellement corrompu et peut accorder des privilèges non autorisés.
Injection XPath
python
query = f"//users/user[username/text()='{user}']"
Entrée malveillante :
bash
ou '1'='1
Cela expose les enregistrements d'utilisateurs non autorisés.
XXE Charge utile
xml
<!DOCTYPE foo [
]>&payload;
Manipulation des schémas
xml
<xs:element name="amount" type="xs:string"/>
Cela désactive le comportement de validation attendu.
Billion Laughs DoS
xml
<!ENTITY a "ha"><!ENTITY b "&a;&a;"><!ENTITY c "&b;&b;">
L'expansion massive surcharge l'analyseur.
Techniques défensives
Désactiver la résolution des entités
python
parser = etree.XMLParser(resolve_entities=False, no_network=True)
Utiliser des bibliothèques sûres
python
import defusedxml.ElementTree en tant que ET
Validation solide des schémas
python
schema.validate(input_xml)
Ne jamais concaténer des chaînes XML
Une approche plus sûre :
python
el = Element("user") name_tag.text = user_input
Tableau de comparaison
| Type | Cible | Sévérité | Impact |
|---|---|---|---|
| Injection XML | Manipulation des structures | Moyenne-élevée | Dérivation logique |
| Injection XPath | Contrôle des requêtes | Haut | Accès non autorisé |
| XXE | Mauvaise utilisation de l'analyseur syntaxique | Haut | Lecture de fichiers / SSRF |
| Injection de schéma | Contournement de la validation | Moyen | Risques liés à l'intégrité |

Injection XML dans les tests de pénétration automatisés
Les plateformes modernes de test de pénétration pilotées par l'IA, telles que Penligent, effectuent des mutations de structure, du fuzzing XML, des tests de charge utile XPath et de la détection de mauvaise configuration de l'analyseur. Ces plateformes :
- Découvrir les surfaces d'attaque basées sur XML
- Identifier les points d'injection
- Apprentissage automatique du comportement des schémas
- Générer des charges utiles adaptatives
- Valider le comportement de l'analyseur sous plusieurs configurations
Cela permet d'étendre considérablement la couverture de la détection.
Lignes de base en matière de sécurité et recommandations automatisées de corrections
Les plateformes automatisées peuvent également fournir :
- Audits de configuration de l'analyseur
- Détection des bibliothèques XML non sûres
- Vérification des paramètres de résolution de l'entité
- Application d'une validation XSD stricte
- Blocage CI/CD des opérations XML non sécurisées
La détection est ainsi transformée en mesures correctives exploitables.
Script pour l'exemple
Règles Semgrep - Injection XML Python / XXE / Parsing non sécurisé
Créer un fichier :
semgrep-rules/python-xml-injection.yaml
yaml
`rules :
RÈGLE 1 : Utilisation non sécurisée de xml.etree - l'analyseur par défaut est vulnérable à XXE
- id : python-unsafe-xml-etree severity : ERROR message : | xml.etree.ElementTree n'est pas sûr pour un XML non fiable. Il ne désactive PAS l'expansion des entités externes par défaut. Utilisez defusedxml à la place. metadata : cwe : "CWE-611" owasp : "A04:2021 XML External Entities" patterns :
- pattern : | import xml.etree.ElementTree as ET langages : [python]
RÈGLE 2 : Utilisation directe de xml.dom.minidom - analyseur XML non sécurisé
- id : python-unsafe-xml-minidom severity : ERROR message : | xml.dom.minidom ne désactive pas les DTDs ou l'expansion ENTITY. Ne l'utilisez PAS pour du XML non fiable. metadata : cwe : "CWE-611" pattern : | import xml.dom.minidom langages : [python]
RÈGLE 3 : XMLParser lxml dangereux avec resolve_entities=True
- id : python-lxml-resolve-entities-enabled severity : ERROR message : | lxml XMLParser() with resolve_entities=True enables XXE. Définir resolve_entities=False et load_dtd=False. metadata : cwe : "CWE-611" motif : | XMLParser(resolve_entities=True, ...) langages : [python]
REGLE 4 : lxml avec load_dtd=True - dangereux
- id : python-lxml-load-dtd severity : WARNING message : | load_dtd=True permet le traitement des DTD et peut permettre l'expansion des entités. Désactiver à moins que cela ne soit absolument nécessaire. metadata : cwe : "CWE-611" pattern : | XMLParser(load_dtd=True, ...) langages : [python]
REGLE 5 : Configuration de l'analyseur syntaxique manquante lors de l'utilisation de lxml.fromstring()
- id : python-lxml-fromstring-no-safe-config severity : WARNING message : | Lxml.fromstring() appelé sans XMLParser renforcé. Assurer resolve_entities=False, no_network=True. metadata : cwe : "CWE-611" motifs :
- pattern : | from lxml import etree - pattern : | etree.fromstring($XML) langages : [python]
RÈGLE 6 : Ne pas utiliser defusedxml lors de l'analyse d'un fichier XML externe
- id : python-defusedxml-not-used severity : INFO message : | Message INFO : python-defusedxml-not-used n'utilise pas defusedxml, recommandé pour l'analyse XML sécurisée en Python. metadata : cwe : "CWE-611" pattern-either :
- motif : | ET.parse($X) - pattern : | etree.parse($X) langages : [python]
RÈGLE 7 : xmltodict sans forcer l'analyseur syntaxique désamorcé
- id : python-xmltodict-unsafe severity : WARNING message : | xmltodict peut invoquer un analyseur XML sous-jacent qui autorise XXE. Utiliser
defusedxmlà la place de l'analyseur syntaxique : | xmltodict.parse($X) langages : [python]
RÈGLE 8 : Utilisation dangereuse de eval() sur des données d'entrée dérivées de XML
- id : python-eval-from-xml severity : CRITICAL message : | eval() sur une entrée dérivée de XML peut conduire à un RCE. Ne jamais évaluer directement les valeurs XML analysées. metadata : cwe : "CWE-95" owasp : "A03:2021 Injection" patterns :
- motif : | $VAL = $XML.xpath(...) - motif : | eval($VAL) langages : [python]
RÈGLE 9 : Chargements pickle.non sûrs sur des données provenant de XML
- id : python-pickle-on-xml severity : CRITIQUE message : | L'utilisation de pickle.loads() sur une entrée dérivée de XML peut conduire à une exécution de code arbitraire. Evitez d'utiliser pickle sur des données utilisateur. metadata : cwe : "CWE-502" motifs :
- motif : | $DATA = etree.fromstring(...) - motif : | pickle.loads($DATA) langages : [python]`
Scanner SAST complet en Python
Il complète Semgrep en recherchant des modèles risqués, notamment :
- Importations non sûres d'analyseurs XML
- ENTITY / DOCTYPE usage
eval,exécuter,cornichon,maréchal,yaml.loadmodèles- Déclencheurs XXE en
.xml,.xsd,.wsdldossiers
Créer : python_sast_scanner.py
python
`#!/usr/bin/env python3″"" python_sast_scanner.py Scanner SAST léger et rapide, spécifique à Python, spécialisé dans les.. :
- Injection XML / XXE
- Utilisation non sûre de l'analyseur syntaxique
- fonctions dangereuses (eval, exec, pickle.loads, yaml.load) Sûr pour CI ; n'exécute pas de code. Produit du JSON et une sortie non nulle en cas de découverte. """import os, re, json, sys PATTERNS = {# XML / XXE "xml_etree" : r "import\s+xml\.etree\.ElementTree", "xml_minidom" : r "import\s+xml\.dom\.minidom", "lxml_resolve_entities" : r "resolve_entities\s*=\sTrue", "lxml_load_dtd" : r "load_dtd\s=\s*True", "doctype_in_xml" : r"<!DOCTYPE", "entity_in_xml" : r"<!ENTITY",

Fonctions dangereuses
"eval_usage": r"\\beval\\s*\\(","exec_usage": r"\\bexec\\s*\\(","pickle_loads": r"pickle\\.loads\\s*\\(","marshal_loads": r"marshal\\.loads\\s*\\(","yaml_unsafe_load": r"yaml\\.load\\s*\\(",
} IGNORED = {".git", "venv", "env", "pycache", "dist", "build", "node_modules"} def scan_file(path) : findings = []try:with open(path, "r", encoding="utf-8″, errors="ignore") as f:for i, line in enumerate(f, 1):for rule, regex in PATTERNS.items():if re.search(regex, line) : findings.append({"rule" : rule, "line" : line.strip(), "lineno" : i, })except Exception:pass return findings def walk(root=".") : results={}for dp, dirs, files in os.walk(root) : dirs[ :] = [d for d in dirs if d not in IGNORED]for f in files:if f.endswith((".py",".xml",".xsd",".wsdl"))) : full = os.path.join(dp, f) hits = scan_file(full)if hits : results[full] = hitsreturn results def main() : root = sys.argv[1] if len(sys.argv)>1 else "." results = walk(root)print(json.dumps({"results" : results, "file_count" : len(results)}, indent=2))if results : sys.exit(3) sys.exit(0) if name = "main" : main()`
Ce qui est couvert - Python SAST Scope
Injection XML / XXE
✔ Analyseurs XML non sûrs ✔ lxml avec resolve_entities=True ✔ Chargement de DTD (potentiellement dangereux) ✔ Marqueurs XXE dans les fichiers XML stockés
Injection de code
✔ eval() ✔ exec()
Désérialisation non sécurisée
✔ pickle.loads() ✔ marshal.loads() ✔ dangereux yaml.load()
Autres schémas dangereux
✔ ENTITY / DOCTYPE en .xml, .xsd, .wsdl ✔ xmltodict sans parser renforcé
Conclusion
L'injection XML reste une catégorie de vulnérabilité pertinente et dangereuse. Son impact va du contournement de la logique d'entreprise à la divulgation de fichiers et au déni de service. Comprendre les comportements XML, sécuriser les analyseurs, valider la structure et incorporer des tests de pénétration automatisés sont des étapes essentielles pour garantir une sécurité robuste des applications.

