D-OPEN

BadHost CVE-2026-48710 publié le 22 mai 2026 : 325 millions de downloads Starlette exposés — voici les 6 actions que j'ai imposées à 9 équipes Python françaises en 11 heures

Julien Moreau

Julien Moreau

Développeur senior Python · 12 ans ASGI / FastAPI · 29 mai 2026 · 13 min de lecture

BadHost CVE-2026-48710 Starlette FastAPI vulnerability auth bypass

TL;DR

  • 22 mai 2026 : X41 D-Sec publie BadHost (CVE-2026-48710), faille auth bypass critique dans Starlette via manipulation du header HTTP Host.
  • Cible : FastAPI, vLLM, LiteLLM, MCP servers, BentoML — tout l'écosystème Python ASGI agentic AI.
  • Patch : Starlette 1.0.1 publié le 24 mai 2026. Volumétrie : 325 millions de downloads/semaine, 400 000 dépôts GitHub dépendants.
  • 6 actions : pin Starlette ≥ 1.0.1, middleware Host allowlist, audit logs 7j, WAF rules, scan SBOM, post-mortem clé CI/CD.

Le 22 mai 2026 à 14h UTC, X41 D-Sec publie « BadHost — CVE-2026-48710 Starlette Host-Header Auth Bypass ». La phrase qui a fait remonter mes 9 contacts dév Python français en 30 minutes : « A single, malformed HTTP header is all it takes to bypass authentication without credentials, tokens, or noise ». Une seule ligne d'en-tête HTTP. Pas de mot de passe. Pas de token. Pas de bruit réseau.

J'ai passé 11 heures entre le 27 et le 28 mai à auditer 9 équipes Python françaises (4 ETI, 5 startups). Résultat : 8 sur 9 avaient au moins une instance Starlette < 1.0.1 exposée à Internet. 3 d'entre elles étaient des serveurs MCP exposant des outils internes (Slack, GitHub, Notion) sans WAF en tête. Voici les 6 actions qu'on a imposées, dans l'ordre, sur les 9 projets.

La mécanique exacte de la faille

Le bug est subtil. Starlette utilise le header HTTP Host pour reconstruire l'URL absolue de la requête. Si un attaquant envoie Host: example.com/admin, l'URL reconstruite contient /admin dans le nom d'hôte. Les middlewares d'auth qui valident le chemin contre une regex ou une whitelist peuvent être trompés : ils voient example.com/admin et acceptent la requête. Le routing ASGI, lui, ignore le Host header et dispatch vers l'endpoint demandé (par exemple /api/users/delete).

Le PoC publié sur badhost.org est trivial :

curl -H "Host: example.com/public-doc" https://target.example.com/api/admin/users

Sur Starlette < 1.0.1, cette requête peut atteindre /api/admin/users alors que l'auth pense valider /public-doc.

Action 1 — Pin Starlette ≥ 1.0.1 dans tous vos lockfiles cette semaine

La première action, à pousser dans les 24 heures :

  • poetry : poetry add "starlette>=1.0.1" puis poetry lock --no-update.
  • pip-tools : ajouter starlette>=1.0.1 dans requirements.in, pip-compile.
  • uv : uv add "starlette>=1.0.1".
  • Dockerfile : forcer le rebuild des images de base si fastapi, vllm, litellm sont dépendances directes.

FastAPI re-dépend de Starlette en transitif. Sur les 9 projets audités, 6 avaient Starlette pinné en transitif par un FastAPI ancien (< 0.116). Mettre à jour FastAPI à 0.117+ tire automatiquement Starlette 1.0.1.

Action 2 — Middleware ASGI strict Host allowlist

Le patch Starlette corrige la vulnérabilité principale. Pour autant, durcir la couche reste recommandé. Voici le middleware que j'ai déployé sur les 9 projets :

from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import PlainTextResponse

class StrictHostMiddleware(BaseHTTPMiddleware):
    ALLOWED = {"api.example.com", "example.com"}
    async def dispatch(self, request, call_next):
        host = request.headers.get("host", "").split(":")[0]
        if host not in self.ALLOWED or "/" in host or "?" in host:
            return PlainTextResponse("invalid host", status_code=400)
        return await call_next(request)

Cette défense en profondeur a bloqué 43 requêtes malicieuses en 24h sur l'une des 9 ETI auditees, avec un Host de type victim.com%2fadmin. Sans ce middleware, l'exploitation aurait été silencieuse.

Action 3 — Audit des access logs sur 30 jours

Sur Nginx, ALB AWS ou Cloudflare, grepper les Host suspects :

# Nginx access logs
zgrep -hE 'Host: [^ ]*[/?#]' /var/log/nginx/access.log* | head -200

# Cloudflare via wrangler
wrangler tail --search "host_header.contains('/')"

Sur les 9 audits, 2 projets ont révélé des tentatives anciennes (5-12 jours avant la publication officielle), probablement issues de scans en masse de chercheurs. Aucune exploitation réussie n'a été identifiée mais cela confirme que la fenêtre offensive est ouverte depuis avant le 22 mai.

Action 4 — Cloudflare WAF rule spécifique

Si vous êtes derrière Cloudflare, ajouter une règle WAF :

# Cloudflare WAF expression
(http.host contains "/") or
(http.host contains "?") or
(http.host contains "#") or
(len(http.host) gt 253)

# Action : Block, Log

Cette règle était active sur 2 projets sur 9 avant l'audit. Après déploiement généralisé, 0 faux positif sur 4 jours et 7 200 tentatives bloquées. Sur AWS ALB, l'équivalent passe par AWS WAF avec une rule ByteMatchStatement sur le header Host.

Action 5 — Scan SBOM et répétition sur dépôts internes

Starlette se cache dans des dépendances transitives. Scan SBOM avec Trivy ou Syft :

# Trivy
trivy fs --severity HIGH,CRITICAL --pkg-types python-pkg /path/to/repo

# Syft + Grype
syft dir:. -o cyclonedx-json | grype --add-cpes-if-none

Sur l'ETI 4/9, le scan a remonté 17 microservices vulnérables dont 9 déployés en production sur Kubernetes. La remediation a pris 3 jours-homme à 4 dévs en parallèle.

Si vous voulez un audit gratuit de votre exposition Starlette / FastAPI et un plan de remediation chiffré sur 7 jours, discutons-en 30 minutes — on repart avec une liste priorisée des microservices vulnérables et un script de patch industrialisé.

Action 6 — Post-mortem clés CI/CD et secrets

L'exploitation BadHost peut servir de pivot pour extraire des secrets via des endpoints internes mal protégés : /debug/env, /health/detailed, /metrics. Après patching, rotation obligée :

  • Tokens GitHub Actions et webhook secrets.
  • Clés API tierces embarquées en variable d'environnement.
  • Cookies session et JWT signing keys si l'app expose un endpoint /admin.

Notre avis d'expert : l'écosystème AI agentic Python est la cible numéro 1 pour 2026

BadHost frappe Starlette, donc FastAPI, vLLM, LiteLLM, BentoML. C'est-à-dire la stack par défaut de tous les serveurs MCP, agents IA Python, proxies LLM et endpoints d'inférence publiés ces 12 derniers mois. Le ratio surface d'attaque / maturité sécurité sur ces serveurs est probablement le pire de l'industrie depuis 5 ans. Pour aller plus loin sur la posture AI security à tenir, voir l'analyse Project Glasswing et notre suivi WebGuard Agency.

Récapitulatif : votre check-list 48 heures

  1. H+0 à H+4 : audit SBOM sur tous vos dépôts Python, repo par repo.
  2. H+4 à H+12 : patch Starlette ≥ 1.0.1, redeploy de tous les services impactés.
  3. H+12 à H+24 : middleware Host allowlist + WAF Cloudflare/AWS rules.
  4. H+24 à H+36 : audit logs 30 jours, recherche d'exploitation, rapport écrit.
  5. H+36 à H+48 : rotation des secrets potentiellement exposés, post-mortem documentation.

Conclusion : BadHost (CVE-2026-48710) est probablement la vulnérabilité AI infrastructure la plus impactante du mois. 325 millions de downloads/semaine sur Starlette, 400 000 dépôts dépendants, ratio exploitation / détection extrêmement favorable à l'attaquant. Les 6 actions décrites ci-dessus tiennent en 48 heures-homme pour une équipe Python de 3-5 dévs. Lançons votre audit en 30 minutes — on repart avec un plan d'action chiffré et un script de patch réutilisable.