BadHost (CVE-2026-48710): One line in the Host header switches auth off — Starlette, FastAPI and every MCP server below 1.0.1 are the line
27 May 2026. X41 D-Sec disclosed the BadHost vulnerability (CVE-2026-48710) in the Starlette ASGI framework on 22 May, as part of an OSTIF-funded vLLM audit. A single line in the HTTP Host header is enough to bypass path-based auth middleware; request.url.path is rebuilt from the Host header, while ASGI routing operates on the raw path — a classic path-confusion pattern that triggers in any Python stack with FastAPI, vLLM, LiteLLM or a Model Context Protocol server. Starlette 1.0.1 from 21 May closes the gap; for Moselwal clients running their own MCP stack or FastAPI backends, the bump belongs in the next maintenance window.
![Aufsicht-Stillleben auf einer matt-dunklen Schieferfläche als Arbeitstisch eines Routing-Auditors. Im Zentrum eine kreisrunde niedrige Sortier-Tablette aus brüniertem Messing mit einem dünnen Mittel-Steg, der die Tablette in zwei Pigeonholes teilt — die linke gestempelt /public/discovery, die rechte gestempelt /admin/settings, beide in monospaced Letterpress. Quer über dem Steg liegt ein einzelner cremefarbener Brief: die obere Hälfte gestempelt Host: example.com/.well-known/ ragt in die /public-Pigeonhole, die untere Hälfte mit dem Slip path: /admin/settings ragt in die /admin-Pigeonhole. Auf der oberen /public-Hälfte sitzt ein einzelner oxblutroter Wachstropfen mit einem brünierten Messing-Petschaft als Auth-Stempel. Links unten ein aufgeschlagenes leinenbespanntes Audit-Hauptbuch mit drei monospaced Bleistift-Einträgen, einer davon lesbar scope["path"], daneben ein cremefarbenes Karteikärtchen mit der monospaced Letterpress-Aufschrift CWE-444. Rechts oben im Negativraum ein brünierter Messing-Stempel mit Walnussgriff und ein zweites Karteikärtchen mit der Letterpress-Aufschrift Starlette 1.0.1. Kühles Studio-Schlüssellicht von oben links, sanftes warmes Rim-Licht von unten rechts; Hintergrund verläuft ins Schiefergrau und Beinahe-Schwarz am rechten Bildrand, für das Title-Overlay frei.](/fileadmin/_processed_/0/c/csm_mcp-bad-host_03bbdc9336.png)
TL;DR — the 90-second summary
- What was published?
An authentication bypass in Starlette < 1.0.1, the ASGI framework that underpins FastAPI, vLLM, LiteLLM, the official Model Context Protocol Python SDK and, per OSTIF estimate, more than 400,000 GitHub repositories. CVE-2026-48710, class CWE-444 (Inconsistent Interpretation of HTTP Requests / HTTP Request Smuggling), public since 22 May 2026 together with the scanner domain badhost.org.
- How severe?
X41 D-Sec rates it CVSS 7.0 (High), the Starlette maintainer 6.5 (Moderate). The gap rests on one assumption: the maintainer reads path-based auth as an anti-pattern and the class as narrow; the auditor reads path-based auth as the default pattern across MCP servers, FastAPI auth decorators and reverse-proxy setups — that is, as broad reality. X41 used CodeQL scans to identify stacks where the bypass escalated to RCE through secondary effects.
- What is the technical lever?
Starlette builds
request.urlvia string concatenation from the Host header and the path. If the Host header contains/,?or#, the URL boundary shifts on re-parse; the ASGI server still routes against the raw path inscope["path"], while middleware readsrequest.url.pathand sees something different.- Why is MCP particularly exposed?
The Model Context Protocol specification mandates unauthenticated OAuth discovery endpoints —
/.well-known/oauth-authorization-server,/.well-known/oauth-protected-resource,/.well-known/openid-configurationare public by design. Those paths give the most reliable Host header substitution. An MCP server that uses path-prefix auth for/tools,/resourcesor/promptshands the attacker three public discovery paths.- Am I affected as a Moselwal client?
Directly, if you run your own MCP server (Anthropic connector, internal tools), a FastAPI application, a vLLM or LiteLLM deployment or an OpenAI-shim proxy. Indirectly, through transitive dependencies in nearly every modern Python AI stack — Starlette is a required dependency of FastAPI and therefore of a broad class of agent harness components.
- Immediate mitigation without the patch?
At the reverse proxy (nginx, Traefik, Caddy, AWS ALB): normalise the Host header server-side to the expected domain, and reject slashes, question marks and hash signs in the Host header. In the auth middleware: use
scope["path"]instead ofrequest.url.path— that is the path the router actually decides on. Both solve the class, but the pull to Starlette 1.0.1 is the shorter route.
What happened
The disclosure chain is documented soberly. X41 D-Sec identified BadHost on 27 January 2026 during an OSTIF-funded audit (Open Source Technology Improvement Fund) of the vLLM inference server. The coordinated report reached the Starlette maintainers on 4 February with a working proof of concept; acknowledgement on 5 February. A patch proposal landed on 1 March, but the actual Starlette 1.0.1 release shipped only on 21 May — nearly three months after the patch proposal. Public disclosure followed on 22 May, alongside the scanner domain badhost.org and X41’s detector tooling. The picture has since been covered broadly across the relevant tech briefings (CSO Online, InfoWorld, Cyber Kendra, Help Net Security, SC Media); the Hacker News thread has crossed into three-digit comment counts. The German BSI has, as of today, not published an advisory of its own.
Technical context
Structurally, BadHost is a path-confusion incident in CWE-444. Starlette rebuilds request.url via a string concatenation f"{scheme}://{host}{path}{query}{fragment}", where host comes directly from the HTTP Host header. The composed URL is then re-parsed; a / in the Host header shifts the path boundary, a ? the query boundary, a # the fragment boundary. The result: request.url.path is a different string than scope["path"]. The ASGI server (uvicorn, hypercorn) routes against scope["path"]; any middleware that reads request.url.path sees the manipulated variant.
In CVSS terms, and this is where the discrepancy between maintainer and auditor sits: AV:N (network), AC:L (low complexity), PR:N (no privileges — an open endpoint such as an MCP discovery path is sufficient), UI:N (no user interaction), Scope:Changed or Unchanged depending on the stack, C:H/I:H/A:L. The maintainer assumes Scope:U and lower confidentiality impact, because they read path-based auth as an anti-pattern; X41 assumes Scope:C, because in real-world FastAPI and MCP codebases auth runs precisely on request.url.path, and the auth bypass therefore opens the full protected endpoint surface.
What this means for the German Mittelstand
Across our client base, Starlette sits in three classes of stacks. First: an in-house MCP server for internal tool integration in Claude or Anthropic agent workflows. That is the class with the sharpest exposure — the OAuth discovery paths are public, the tool endpoints are protected by path-prefix auth, and that architecture is the BadHost textbook case. Second: FastAPI backends in platform services (form intake, webhook endpoints, AI function wrappers, internal admin APIs). The auth class here is more heterogeneous, but path-prefix checks are a common pattern. Third: transitive exposure through vLLM (inference server for open-weight models) and LiteLLM (OpenAI-shim proxy for multi-model routing); both use Starlette as their HTTP layer, and both have been widely adopted in the self-hosted, sovereign-hosting trend of the past months.
On the compliance side, the incident touches several axes. NIS-2 Article 21 requires patch discipline along the supply chain, and Starlette is a supply-chain component. BSI APP.6 (General Software) and APP.4 (Business Applications) carry the finding; an MCP server architecture also lands under BSI APP.4.2 (Databases) or APP.4.3 (Server Web Applications), depending on its shape. GDPR Article 32 applies to every pipeline that channels personal data through the MCP tool layer — an auth bypass on a tool endpoint is a confidentiality breach. For DORA-bound firms (financial services), the finding moves into the ICT third-party register; for MaRisk institutions, into the next internal control round. EU AI Act Article 25 (deployer obligations) applies on top for AI systems in the high-risk scope.
What this means for the technical trajectory
Methodologically a pattern emerges that we have seen repeatedly in the daily news of the last two weeks. OSTIF-funded audits produce substantive findings on widely deployed open-source components in a reproducible way — that was the case for the Mythos/Glasswing audit wave on Symfony and Twig in April and May, and it is the case here in the vLLM audit. The funding layer is not incidental: an open-source maintainer team on its own would probably not have bridged the three months between patch proposal and release at this quality, had the disclosure chain not been carried by a dedicated audit organisation. The lesson for the Mittelstand is not “use more open source” or “less”, but: for stack components with broad deployment, it is worth checking whether a documented audit source exists.
Architecturally, the sharpest lesson sits in auth discipline. Path-based auth middleware is not an anti-pattern per se — in many architectures it is the only practical model, for instance when the reverse proxy has no access to the internal auth logic or when the application itself carries the auth rules. What the class requires is checking the source: scope["path"] (that is, the path the ASGI server actually routes against) is the only reliable string for an auth decision; request.url.path is the convenience object that can flip at any time, the moment a component in the chain interprets a header differently. This separation is not specific to Starlette; it is a general discipline for all HTTP frameworks where URL and path are rebuilt from different sources.
Concrete actions
In this order. First, inventory today all Python ASGI stacks that have Starlette as a direct or transitive dependency: in-house MCP servers, FastAPI backends, vLLM and LiteLLM deployments, OpenAI-shim proxies, agent harness components. pip show starlette and pipdeptree --reverse starlette give the overview. Second, pull Starlette to 1.0.1 in a test pipeline and run a smoke test against the auth paths (internal curl with a manipulated Host header, test against the discovery endpoints). Third, in architectures with path-prefix auth: check whether the middleware uses scope["path"] or request.url.path, and switch to scope["path"] if it is the latter. Fourth, in the reverse proxy (nginx, Traefik, Caddy, AWS ALB), enable Host header normalisation — reject slashes, question marks and hash signs in the Host header. If these four steps cannot run from your own capacity, talk to us: Moselwal builds MCP and FastAPI stacks in which auth discipline runs along scope["path"] rather than request.url.path.
This post reflects our technical and strategic assessment. It does not replace legal advice or a data protection impact assessment.
Sources
- OSTIF — Disclosing the BADHOST Vulnerability in Starlette (22 May 2026)
- badhost.org — CVE-2026-48710 Starlette Host Header Auth Bypass, scanner and detail page (22 May 2026)
- CSO Online — FastAPI-based AI tools exposed to authentication bypass by flaw in Starlette framework (22 May 2026)
- Cyber Kendra — BadHost (CVE-2026-48710): One Rogue Header Line Unlocks Your Entire AI Stack (22 May 2026)
- OffSeq Threat Radar — CVE-2026-48710 CWE-444 Inconsistent Interpretation of HTTP Requests in Kludex starlette (as of 22 May 2026)

![[Translate to English:] Foto von Kai Ole Hartwig.](/fileadmin/_processed_/e/9/csm_ole-neu_73323ad80d.jpeg)