# BadHost CVE-2026-48710 — Starlette HTTP Host Header Authentication Bypass Affecting FastAPI/AI Infrastructure (MCP, vLLM, LiteLLM)

> BadHost (CVE-2026-48710) is a critical authentication bypass vulnerability in Starlette versions prior to 1.0.1, the ASGI framework underlying FastAPI. The flaw stems from unsafe concatenation of the HTTP Host header into request.url construction, allowing attackers to inject path-like values (e.g., 'Host: example.com/health?x=') that cause request.url.path to differ from the actual routed path. Authentication middleware relying on request.url.path can be bypassed entirely. The vulnerability disproportionately impacts AI infrastructure including MCP (Model Context Protocol) servers, vLLM, LiteLLM, Ray Serve, BentoML, and Google ADK-Python. Discovered by X41 D-Sec during an OSTIF-sponsored audit funded by the Alpha-Omega Project.

- **Published:** 2026-05-27T00:00:00Z
- **Last reviewed:** 2026-05-27T00:00:00Z
- **Canonical:** https://intel.threadlinqs.com/threat/TL-2026-0606
- **ID:** TL-2026-0606
- **Severity:** CRITICAL (CVSS 6.5)
- **Category:** VULNERABILITY
- **Status:** ACTIVE
- **Detections:** 9 · **IOCs:** 18 (full data via the Threadlinqs MCP server — Purple tier)
- **CVEs:** CVE-2026-48710

## Description

## Overview

BadHost (CVE-2026-48710, X41-2026-002, GHSA-86qp-5c8j-p5mr, PYSEC-2026-161) is an HTTP Host header injection vulnerability in Starlette, the ASGI web framework that powers FastAPI and most modern Python AI/agent serving infrastructure. The flaw allows an unauthenticated remote attacker to bypass path-based authentication middleware by injecting characters such as `/`, `?`, `#`, `@`, `\`, or whitespace into the HTTP Host header. The vulnerability affects every Starlette release prior to 1.0.1 (operationally relevant from 0.8.3 onward) and is fixed in 1.0.1, released 2026-05-21.

## Root Cause

Starlette reconstructs `request.url` by concatenating the HTTP `Host` request header with the ASGI `scope["path"]` and re-parsing the result through Python''s `urlsplit()` — without validating the Host value against RFC 9110 §7.2 / RFC 9112 §3.2 / RFC 3986 §3.2.2 grammar (`uri-host [ ":" port ]`). The vulnerable logic lives in `starlette/datastructures.py` (the `URL` class), consumed by `Request.url` in `starlette/requests.py`.

Conceptually, the vulnerable assembly behaves like:

```
url = f"{scheme}://{host_header}{scope[''path'']}"
parsed = urlsplit(url)
# parsed.path is now derived from host_header + scope[''path''], not from scope[''path''] alone
```

The critical consequence is a **parser disagreement** between two consumers of the same request:

1. The ASGI server / Starlette router dispatches against the raw wire path (`scope["path"]`).
2. Any middleware that inspects `request.url.path` sees a re-parsed path that can be shifted by attacker-controlled characters in the Host header.

Authorization built on `request.url.path` therefore evaluates a different string than the route actually executed. Python''s `urlsplit()` is lenient and accepts characters that are illegal in a valid RFC host, producing the cleavage.

## Exploit Primitive

The canonical proof of concept:

```
GET /admin HTTP/1.1
Host: example.com/health?x=
```

Reconstructed URL becomes `http://example.com/health?x=/admin`. After re-parse:
- `request.url.path` = `/health` (passes any allowlist for unauthenticated paths)
- ASGI routed path = `/admin` (still dispatched to the protected handler)
- Middleware permits the request; the protected handler executes and returns 200 OK

A single trailing `?`, `/`, or `#` appended to the Host header is sufficient. Standard HTTP clients (browsers, `requests`, `urllib`) normalize Host and will not deliver the malformed value — exploitation requires raw sockets, low-level libraries, or `curl` with an explicit `-H 'Host: foo?'` override.

## Why MCP Servers Are Disproportionately Exposed

The Model Context Protocol (MCP) specification mandates two unauthenticated OAuth discovery endpoints on every spec-compliant MCP server:

- `/.well-known/oauth-authorization-server`
- `/.well-known/oauth-protected-resource`

These paths are guaranteed unauthenticated by design. An attacker therefore has a pre-built skeleton key for bypassing path-based middleware:

```
GET /mcp/tools/execute HTTP/1.1
Host: target.example.com/.well-known/oauth-authorization-server?x=
```

Middleware evaluates the OAuth discovery path (allowlisted) while the router dispatches `/mcp/tools/execute`. The attacker invokes MCP tools, exfiltrates API keys, and accesses internal tooling — all without credentials. Persistent Security Industries (Nemesis) operates a public scanner (`mcp-scan.nemesis.services`) that probes `/mcp`, `/sse`, `/messages`, and the `.well-known` OAuth endpoints to identify exposed MCP instances.

## Downstream Blast Radius

Because Starlette is a transitive dependency of much of the Python AI/agent serving ecosystem, the vulnerability impacts:

- **FastAPI** — directly built on Starlette. All apps using `BaseHTTPMiddleware` with `request.url.path` auth checks are affected. Route-level `Depends()` / `Security()` dependencies are NOT affected.
- **vLLM** — high-performance LLM inference server. The bug was originally discovered here during the audit.
- **LiteLLM** — LLM proxy gateway. `/model/info`, `/key/info` endpoints exposed; direct API key exfiltration risk.
- **MCP servers** — highest risk class due to mandated unauthenticated `.well-known` paths.
- **Ray Serve**, **BentoML**, **Google ADK-Python**, **Text Generation Inference**, agent harnesses, eval dashboards, model registries.
- **Apache Airflow** — PR #3279 cites two concrete bypasses: `JWTAuthStaticFiles.validate_jwt_token` log-file auth bypass and Edge3 worker API auth bypass. Upgraded to Starlette 1.0.1.

## Escalation

The authentication bypass is the primitive; the impact depends on what protected functionality the application exposes. Documented escalations include:

1. Authentication bypass on path-gated middleware
2. Access to admin/management endpoints (`/admin`, `/v1/models`, `/internal`, `/metrics`, `/shutdown`)
3. SSRF via gated proxy endpoints — reaching cloud metadata services and internal networks
4. RCE when reached endpoints execute tools, load models from URLs, or evaluate code — confirmed across multiple downstream AI projects

## Fix

The patch (encode/starlette PR #3279 by Marcelo Trylesinski / Kludex, commit `764dab0dcfb9033d75442d7a359645c9f94648c6`) introduces a strict allowlist regex (`_HOST_RE`) in `starlette/datastructures.py` matching only valid `[a-zA-Z0-9.-]` domain labels, IPv6 in brackets, and an optional `:port`. If the Host header fails the regex, Starlette falls back to `scope["server"]` (host+port from the ASGI scope) — identical to the no-Host-header path. Released as **Starlette 1.0.1** on 2026-05-21.

## Detection & Mitigation

- Deploy an RFC-compliant reverse proxy (nginx, Apache, Caddy, Traefik, HAProxy, Cloudflare, AWS ALB) in front of any directly-exposed Starlette/FastAPI service — these reject invalid characters in Host headers.
- WAF rule: drop requests where the Host header contains `/`, `?`, `#`, `@`, `\`, or whitespace.
- Replace `request.url.path` with `request.scope["path"]` in custom middleware. The ASGI scope path is not influenced by the Host header.
- Prefer FastAPI route-level `Depends()` / `Security()` and Starlette `requires()` over `BaseHTTPMiddleware` path-prefix checks.
- Run X41''s published Semgrep and CodeQL rules to identify unsafe `request.url.path` usage in your codebase.
- Upgrade Starlette to ≥ 1.0.1 (transitively re-pin FastAPI, vLLM, LiteLLM, Ray Serve, BentoML, ADK-Python, MCP servers).

## Discovery

Identified by X41 D-Sec senior researchers (JJ, Yassine El Baaj, Markus Vervier) on 2026-01-27 during manual source review of vLLM in an OSTIF-managed audit sponsored by the Alpha-Omega Project. Privately disclosed to Starlette maintainers 2026-02-04, patched 2026-05-21, publicly disclosed 2026-05-22.

## MITRE ATT&CK

- T1595 Active Scanning
- T1592 Gather Victim Host Information
- T1587 Develop Capabilities
- T1588 Obtain Capabilities
- T1190 Exploit Public-Facing Application
- T1059 Command and Scripting Interpreter
- T1211 Exploitation for Stealth
- T1685 Disable or Modify Tools
- T1552 Unsecured Credentials
- T1528 Steal Application Access Token
- T1046 Network Service Discovery
- T1526 Cloud Service Discovery
- T1213 Data from Information Repositories
- T1102 Web Service
- T1496 Resource Hijacking

## Sources

- [X41 D-Sec Advisory X41-2026-002 — Starlette HTTP Host Header Authentication Bypass](https://x41-dsec.de/lab/advisories/x41-2026-002-starlette/)
- [GHSA-86qp-5c8j-p5mr — Starlette mishandles malformed Host header](https://github.com/encode/starlette/security/advisories/GHSA-86qp-5c8j-p5mr)
- [Starlette PR #3279 — Ignore malformed Host header when constructing request.url](https://github.com/encode/starlette/pull/3279)
- [Starlette fix commit 764dab0](https://github.com/encode/starlette/commit/764dab0dcfb9033d75442d7a359645c9f94648c6)
- [Starlette 1.0.1 Release](https://github.com/encode/starlette/releases/tag/1.0.1)
- [PyPA Advisory PYSEC-2026-161 — Starlette](https://github.com/pypa/advisory-database/blob/main/vulns/starlette/PYSEC-2026-161.yaml)
- [NVD — CVE-2026-48710](https://nvd.nist.gov/vuln/detail/CVE-2026-48710)
- [Tenable — CVE-2026-48710](https://www.tenable.com/cve/CVE-2026-48710)
- [BadHost Project Portal](https://badhost.org/)
- [SecWest — Starlette BadHost analysis](https://www.secwest.net/starlette)
- [OSTIF — Disclosing the BadHost Vulnerability in Starlette](https://ostif.org/disclosing-the-badhost-vulnerability-in-starlette/)
- [X41 PoC repository — scanner, Semgrep, CodeQL](https://github.com/x41sec/poc/tree/master/starlette-host-header)
- [BadHost MCP scanner (Nemesis)](https://mcp-scan.nemesis.services/)
- [Cybersecurity News — Attackers Can Exploit BadHost to Access Sensitive AI Agent Server Endpoints](https://cybersecuritynews.com/badhost-ai-agent-vulnerability/)
- [CSO Online — FastAPI-based AI tools exposed to authentication bypass by flaw in Starlette framework](https://www.csoonline.com/article/4177711/fastapi-based-ai-tools-exposed-to-authentication-bypass-by-flaw-in-starlette-framework.html)

## Full data

Detection queries (Splunk SPL / Microsoft KQL / Sigma) and IOC values require the Threadlinqs MCP server (Purple tier): https://intel.threadlinqs.com/mcp

Canonical: https://intel.threadlinqs.com/threat/TL-2026-0606
