CVE-2026-48710 : BadHost — contrebande de chemin HTTP et contournement d'authentification dans starlette & FastAPI
HERMES THREAT SCORE & EXPLOITABILITÉ OPÉRATIONNELLE
Cible :Framework ASGI Starlette & Microservices FastAPI (≤ 1.0.0) Élevé à 92 HIGH par Hermes en raison de son adoption massive dans les passerelles d'inférence d'IA (vLLM, LiteLLM, serveurs d'agents), d'une exploitation active dans la nature et de son inclusion au catalogue CISA KEV (2 septembre 2026).
CVE-2026-48710: Starlette & FastAPI BadHost Path Smuggling & Auth BypassVULNÉRABILITÉ
Software platform affected by security vulnerabilities and agentic attack patterns.
🔍 Pourquoi cette relation ? (Preuves & Provenance)
“Confirmed security vulnerability in Starlette / FastAPI ASGI Framework documented in Hermes dossier.”
- [vulnerability_report]
- [government_confirmation]CISA verified active exploitation in the wild and mandated federal remediation deadline in KEV entry. — Source : Cybersecurity & Infrastructure Security Agency (CISA): CISA Adds CVE-2026-59822 to Known Exploited Vulnerabilities Catalog (Fiabilité : VERY_HIGH)
Analyse de la cause racine (root cause)
Section intitulée « Analyse de la cause racine (root cause) »Dans les architectures web asynchrones en Python, la spécification ASGI (Asynchronous Server Gateway Interface) orchestre les échanges entre le serveur HTTP (Uvicorn, Hypercorn, Granian) et le framework applicatif (Starlette, FastAPI) :
Désynchronisation entre le Scope ASGI et Starlette request.url (« BadHost ») :
L'Attaquant Soumet une Requête Forgée : GET /admin/models/delete HTTP/1.1 Host: api.cible.corp/public# │ ▼ [Serveur ASGI : Uvicorn / Hypercorn] Découpage standard du paquet HTTP en dictionnaire de scope ASGI : scope = { "type": "http", "path": "/admin/models/delete", <── Chemin Réel d'Exécution "headers": [(b"host", b"api.cible.corp/public#")] } │ ▼ [Couche Applicative Starlette : request.py] Reconstruction de l'objet `request.url` par interpolation brute de chaînes : url = f"{scheme}://{host}{root_path}{path}" url = "https://" + "api.cible.corp/public#" + "" + "/admin/models/delete" │ ▼ [Analyseur de la Bibliothèque Standard urllib.parse.urlsplit(url)] Interprète `#` comme délimiteur de fragment ou `/` comme délimiteur de chemin : • scheme : "https" • netloc : "api.cible.corp" • path : "/public" <── CHEMIN ÉVALUÉ TRONQUÉ • fragment : "/admin/models/delete" │ ▼ Évaluation par le Middleware de Sécurité : ┌────────────────────────────────────────────────────────────────────────┐ │ Middleware d'Auth : `if request.url.path.startswith("/admin"): exiger_cle()`│ │ Évaluation : `request.url.path` == "/public" -> AUTORISÉ (SANS AUTH) │ └────────────────────────────────────────────────────────────────────────┘ │ ▼ Exécution par le Routeur ASGI Sous-Jacent : Le routeur utilise `scope["path"]` -> Exécute `/admin/models/delete`Le défaut d’interpolation de l’en-tête Host
Section intitulée « Le défaut d’interpolation de l’en-tête Host »Dans les versions de Starlette antérieures à la 1.0.1, la propriété Request.url dans starlette/datastructures.py reconstruisait l’URL absolue en lisant directement l’en-tête client :
# Code vulnérable dans Starlette <= 1.0.0@propertydef url(self) -> URL: if not hasattr(self, "_url"): host_header = self.headers.get("host") if host_header: url = f"{self.scope['scheme']}://{host_header}{self.scope['path']}" else: server = self.scope.get("server") url = f"{self.scope['scheme']}://{server[0]}:{server[1]}{self.scope['path']}" self._url = URL(url) return self._urlL’en-tête host_header était inséré sans aucune validation de conformité avec la grammaire RFC 9112 (Syntaxe Host HTTP/1.1) ou RFC 3986 (Composants d’Autorité URI).
Lorsqu’un attaquant transmet un en-tête contenant des caractères /, ? ou # (comme Host: exemple.com/public? ou Host: exemple.com/docs#), l’analyseur urllib.parse.urlsplit() redéfinit les limites de l’URL. Le véritable chemin sollicité (/admin/private) est relégué dans les paramètres de requête ou dans le fragment d’ancre, tandis que request.url.path ne reflète que le préfixe factice injecté (/public).
Puisque les middlewares (décorateurs d’authentification FastAPI, filtres RBAC) examinent request.url.path, alors que le moteur de routage interne de Starlette distribue la requête selon le chemin brut scope["path"], les deux mécanismes se désynchronisent complètement.
Mécanique d’exploitation & scénarios d’attaque
Section intitulée « Mécanique d’exploitation & scénarios d’attaque »L’exploitation s’opère par simple émission d’une requête HTTP sans nécessiter de jeton préalable :
1. Contournement de contrôle d’accès d’administration
Section intitulée « 1. Contournement de contrôle d’accès d’administration »Considérons un microservice FastAPI protégeant une route d’administration d’un modèle d’IA :
@app.middleware("http")async def verify_admin_token(request: Request, call_next): # Contrôle de sécurité basé sur request.url.path if request.url.path.startswith("/admin"): token = request.headers.get("X-Admin-Key") if token != "CLE_SECRETE_PRODUCTION": return Response(status_code=403, content="Interdit") return await call_next(request)
@app.post("/admin/models/unload")def unload_model(name: str): return {"status": "modèle déchargé", "target": name}L’attaquant transmet une requête HTTP/1.1 manipulant l’en-tête Host :
POST /admin/models/unload?name=llama3-70b HTTP/1.1Host: passerelle-ia.corp/health#User-Agent: Mozilla/5.0Content-Type: application/json
{}Déroulement de l’attaque :
- Starlette reconstruit :
https://passerelle-ia.corp/health#/admin/models/unload?name=llama3-70b. request.url.pathvaut strictement"/health".- Le middleware vérifie
"/health".startswith("/admin")->Faux. Le contrôle de sécurité est contourné. - Le routeur ASGI prend le relais, consulte
scope["path"](/admin/models/unload), et exécute la fonction administrative. - Le modèle est déchargé de la mémoire GPU sans aucune clé d’administration.
2. Impact sur les passerelles d’agents et serveurs d’inférence
Section intitulée « 2. Impact sur les passerelles d’agents et serveurs d’inférence »- Extraction d’instructions système et RAG : contournement des filtres sur
/admin/promptsou/api/v1/tools, exposant les bases vectorielles et les prompts système propriétaires. - Déni de service GPU : déclenchement d’opérations lourdes de régénération ou de changement de modèles sans authentification ni limitation de débit (rate limiting).
- Rupture d’isolation multi-tenant : dans les architectures SaaS segmentant les clients par chemin d’URL (
/tenants/{id}/...), manipulation des requêtes pour accéder aux contextes d’entreprises tierces.
Indicateurs forensiques & règles de détection
Section intitulée « Indicateurs forensiques & règles de détection »Les équipes DFIR doivent analyser les artefacts suivants :
1. Télémétrie des proxys et pare-feu applicatifs (WAF)
Section intitulée « 1. Télémétrie des proxys et pare-feu applicatifs (WAF) »- Délimiteurs illégaux dans le champ host : requêtes HTTP dont l’en-tête
Hostcontient les caractères/,?,#ou@:GET /admin/keys HTTP/1.1 | Host: 10.0.4.12/public# | Statut: 200 - Anomalies de statut : requêtes ciblant des routes d’administration renvoyant
200 OKdepuis des adresses IP n’ayant jamais initié de flux d’authentification OAuth2 ou d’échange de clé API.
Règles de détection
Section intitulée « Règles de détection »title: En-Tête HTTP Host Malformé Contenant des Délimiteurs d'URL (CVE-2026-48710 BadHost)id: 48710b01-4f10-4e2b-a487-100000048710status: experimentaldescription: Détecte les requêtes HTTP portant des caractères illégaux (/ ? # @) dans l'en-tête Host, caractéristiques de l'exploitation de la contrebande de chemin CVE-2026-48710 dans Starlette/FastAPI.references: - https://github.com/encode/starlette/security/advisories/GHSA-7488-6r32-c95q - https://www.cisa.gov/known-exploited-vulnerabilities-catalogauthor: Hermes Codex CTIdate: 2026-09-08logsource: category: webserver product: web_proxydetection: selection_host: cs-header_host|re: '.*[\/\?\#\@].*' condition: selection_hostfalsepositives: - Outils internes très anciens non conformes aux RFC (très rare en exposition publique).level: hightags: - attack.initial_access - attack.t1190 - cve.2026.48710alert http any any -> $HTTP_SERVERS any ( \ msg:"HERMES CODEX - Tentative de Contrebande BadHost Starlette/FastAPI (CVE-2026-48710)"; \ flow:established,to_server; \ http.host; pcre:"/[\/\?\#\@]/"; \ classtype:web-application-attack; \ sid:202648710; rev:1; \ reference:cve,2026-48710; \ reference:url,https://github.com/encode/starlette; \)Matrice de remédiation
Section intitulée « Matrice de remédiation »1. Mise à niveau impérative
Section intitulée « 1. Mise à niveau impérative »Mettre à niveau l’ensemble des environnements Python vers Starlette 1.0.1 ou supérieure :
# Vérifier la version installéepip show starlette
# Appliquer le correctif officielpip install --upgrade "starlette>=1.0.1"
# Mettre à jour les dépendances FastAPIpip install --upgrade "fastapi>=0.115.0"Dans Starlette 1.0.1, Request.url valide strictement la syntaxe de l’en-tête Host. En cas d’anomalie, le framework se replie sur le tuple d’écoute réseau sécurisé du serveur (scope["server"]).
2. Filtrage au niveau du reverse-proxy (patch virtuel)
Section intitulée « 2. Filtrage au niveau du reverse-proxy (patch virtuel) »Rejeter immédiatement les requêtes malformées au niveau d’Ingress ou de Nginx :
# Règle de filtrage préventive Nginxif ($http_host ~* "[\/\?\#\@]") { return 400 "Bad Request - En-tete Host Invalide";}Sources & références techniques
Section intitulée « Sources & références techniques »- Catalogue CISA KEV : entrée BOD 26-04 pour CVE-2026-48710
- Bulletin de Sécurité GitHub : avis GHSA-7488-6r32-c95q pour Starlette
- Base de Données Nationale des Vulnérabilités (NVD) : fiche détaillée CVE-2026-48710