One malformed Host header bypasses authentication on every Starlette/FastAPI app — including vLLM, LiteLLM, MCP servers, and thousands of AI endpoints. Scan yours in 2 seconds.
Starlette reconstructs request.url from the HTTP Host header. It doesn't validate the header per RFC 9112.
A single ? character in the Host field shifts the path boundary during re-parse. The router dispatches on the real path.
Middleware sees a poisoned path. Any path-based auth decision is bypassed — /admin, /v1/models,
/internal, /metrics.
PoC: curl -i -H 'Host: foo?' http://target/admin โ 200 instead of 403.
Affected: Starlette โฅ0.8.3, <1.0.1 โ FastAPI, vLLM, LiteLLM, TGI, MCP servers, all ASGI apps. Patch: Upgrade Starlette to 1.0.1+.
Identifies framework, ASGI server, and downstream product (vLLM, LiteLLM, FastAPI, MCP) from response headers and body markers.
Sends malformed Host headers (foo?, foo/, foo#) to 20+ sensitive paths. Compares against baseline responses.
Upgrades Starlette to โฅ1.0.1 via pip. Detects container environments and flags Dockerfile rebuild requirements.
Scan 100+ endpoints concurrently from a file. JSON output for CI/CD pipelines. Exit code alerts on any vulnerability.
$ pip install badhost-scanner
$ badhost scan api.myservice.com
โ 2 seconds later โ
๐ด VULNERABLE or ๐ข NOT VULNERABLE
$ badhost patch --dry-run # See what patch would do
$ badhost patch # Auto-patch (free)
# Batch scan your infrastructure
$ cat targets.txt
api.my-vllm.com
litellm-gateway.internal
mcp-server.mycompany.com
10.0.1.50:8000
$ badhost scan-batch targets.txt --concurrent 20
Run badhost scan your-service.com. If any sensitive path returns 200 with a malformed Host header, you're exposed. The scanner tests 20+ common paths and 4 injection patterns.
Most reverse proxies reject malformed Host headers (nginx returns 400). But if your app is reachable directly on a non-standard port, or if HTTP/3 is in play, you should test. The scanner reports "likely patched" if it detects the proxy blocking exploit headers.
The scanner detects container environments and recommends Dockerfile updates. The pip upgrade works in a running container but is lost on restart — you need to rebuild your image with starlette>=1.0.1 pinned.
No. The scan sends HTTP requests and analyses responses. It never writes files or changes configuration. The patch subcommand is opt-in and requires an explicit badhost patch invocation.
Watch mode runs on your schedule (every hour, daily, etc.) and sends you alerts when a scan changes from not vulnerable to vulnerable — useful for catching regressions after deployments.