
Analyse approfondie d'une injection SQL critique dans l'ORM Ormar de Python — reproduction, correctif et tests
Une analyse approfondie d'une vulnérabilité critique (CVSS 9.8) d'injection SQL dans un ORM asynchrone Python, avec reproduction, analyse et correctif.
Ormar est un mini-ORM asynchrone populaire pour Python, couramment utilisé avec FastAPI et Starlette. Les versions 0.9.9 à 0.22.0 contiennent une vulnérabilité d'injection SQL dans les méthodes d'agrégation min() et max().
La cause racine est un bug de « mise en œuvre partielle » : alors que sum() et avg() valident que le paramètre de colonne fait référence à un champ numérique réel, min() et max() ignorent entièrement cette vérification et transmettent l'entrée utilisateur directement à sqlalchemy.text() — un puits SQL brut.
Un attaquant peut injecter une sous-requête comme paramètre « colonne » :
# Utilisation attendue
await Item.objects.max("price") # → SELECT max(price) FROM items
# Charge utile d'attaque
await Item.objects.max("(SELECT password FROM users LIMIT 1)")
# → SELECT max((SELECT password FROM users LIMIT 1)) FROM items
# Renvoie le mot de passe de l'administrateur !
| Attribut | Valeur |
|---|---|
| ID CVE | CVE-2026-26198 |
| Score CVSS | 9.8 (Critique) |
| CWE | CWE-89 : Injection SQL |
| Versions concernées | ormar 0.9.9 – 0.22.0 |
| Corrigé dans | ormar 0.23.0 |
| Publié | 24 février 2026 |
| Authentification requise ? | Aucune — non authentifié |
├── README.md ← Vous êtes ici
├── vulnerable_app.py ← Application FastAPI minimale avec le schéma vulnérable
├── exploit_demo.py ← Preuve de concept sûre montrant l'injection en action
├── patched_app.py ← La version corrigée avec validation des entrées
├── test_vulnerability.py ← Tests prouvant que la vulnérabilité existe et que le correctif fonctionne
├── requirements.txt
└── analysis/
└── root_cause.md ← Analyse détaillée au niveau du code du bug
git clone https://github.com/YOUR_USERNAME/CVE-2026-26198-analysis.git
cd CVE-2026-26198-analysis
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
# Exécuter les tests (aucune base de données externe requise — utilise SQLite)
python -m pytest test_vulnerability.py -v
# Exécuter la démonstration interactive de l'exploit
python exploit_demo.py
Le correctif valide que le paramètre de colonne correspond à un champ réel du modèle avant qu'il n'atteigne sqlalchemy.text(). Cela est réalisé via une approche de liste blanche : seuls les noms de colonnes qui existent dans les définitions de champs du modèle sont autorisés.
Voir patched_app.py pour l'implémentation et analysis/root_cause.md pour l'analyse complète.
sum()/avg() soient validées mais pas min()/max() a créé un faux sentiment de sécurité.MIT