Skip to main content
TechnologyMay 27, 2026· 4 min read

BadHost, the 'one character' bug that exposes thousands of LLM servers worldwide

A single character in the HTTP header Host

is enough to bypass the authorization controls that many Python applications apply based on the request paths. The bug affects Starlette, the ASGI framework behind FastAPI and, consequently, much of the Python infrastructure that today supports model serving, agents, and LLM proxies. The vulnerability is tracked as CVE-2026-48710, named BadHost by the researchers who disclosed it, and already has a patch in version Starlette 1.0.1, released on May 21, followed by public disclosure the next day.

The bug was identified by X41 D-Sec during a code audit of vLLM sponsored by OSTIF. vLLM is one of the most widely used projects for local serving of large models and relies on Starlette via FastAPI. From there, the actual perimeter touches LiteLLM and Text Generation Inference (two gateways between the application and the model), almost all proxies with OpenAI API shims, a large portion of MCP servers, agent harnesses, assessment dashboards, and model control panels.

What exactly does that character do?

To understand how a single injection produces a bypass, it is first necessary to understand how Starlette handles requests. When a client sends an HTTP request command, two pieces of information travel separately: the actual path (for example, /admin) and the Host header, which identifies the recipient domain (for example, example.com). Starlette, to expose to developers a complete request.url object, concatenates the two values and performs a re-parse of the result. Until version 1.0.1, before re-composition, the Host header was not validated against the grammar of RFCs 9112 and 3986: no one checked that the value conformed to the format that Internet specifications impose on the field.

By injecting one of the characters /, ?, or # into the Host header, the attacker shifts the boundaries of path, query, and fragment during the re-parse. The result is that the value of request.url.path seen by the application code after reconstruction no longer corresponds to the path that the ASGI server actually received and against which it performed routing. Two diverging truths are produced: the router routes based on the raw path and then executes the actual endpoint; the middleware, on the other hand, sees the path polluted by reconstruction and applies security controls on the wrong path. Any authentication, authorization, or audit decision based on request.url.path can be bypassed while the protected endpoint continues to execute normally. The researchers' proof-of-concept is a single line: a request with Host: foo to /admin returns 403, while the same request with Host: foo? returns 200.

Why CVSS 6.5 underestimates the real impact

The warning published on the Starlette repository assigns the vulnerability a CVSS score of 6.5 (Moderate), framing the problem strictly at the library level as a simple discrepancy between path strings. The analysis by Secwest, which looked into what the primitive allows downstream projects to do, classifies the bug as critical, and X41 D-Sec in its independent advisory sets the score at 7 (High). The divergence depends on the object evaluated. Looking only at Starlette, the flaw produces a string mismatch; looking at the stacks that consume it, where the middleware relies on request.url for filtering security decisions, the researchers have built proven chains of authentication bypass, SSRF, and remote code execution from the same primitive.

The picture is not reassuring even on another level. Most affected installations are laboratory ones. vLLM, LiteLLM, and similar projects are routinely exposed directly on uvicorn, hypercorn, or granian, i.e., ASGI servers running Python code, without the mediation of a reverse proxy like nginx in front of everything. It is that reverse proxy which, in production sites, discards malformed headers by inertia before they reach the application: its absence in evaluation, development, and research environments leaves the most sensitive routes exposed, such as administration, key management, model management, tool execution, dataset uploading, and submission of fine-tuning jobs.

The arsenal of AI-assisted tools did not intercept the flaw for a specific reason. The over 10,000 high/critical vulnerabilities identified by Mythos of Anthropic in the first month of Project Glasswing are, by design, bugs internal to a single file or repository, where a model can read the code and identify the error. BadHost, on the other hand, lives in the interaction between three independent specifications (HTTP, ASGI, Starlette) and in the usage patterns that downstream projects adopt to read the reconstructed value: each component is correct in isolation, and the flaw emerges only from the composition of layers that, taken separately, all do their job.

The patch is available in Starlette 1.0.1 and requires rebuilding every container, virtualenv, and bundled artifact that locks in the dependency: a simple pip list on the host is not enough, as many LLM installations carry their vendored copy of Starlette. The complementary mitigation, suggested by X41, is to replace request.url.path with request.scope["path"] in middleware, dependencies, and decorators that make security decisions: the second variable returns the raw path without going through reconstruction, effectively closing the class of bugs at the root. For a quick check, a free public scanner managed by the consortium of researchers is available. Patches and public disclosure emerged on the same day, and consequently, the window of advantage for exploit development for exposed operators is assumed to be zero.