

















Security Advisory
Starlette Host Header URL Reconstruction Flaw
CVE-2026-48710 /
GHSA-86qp-5c8j-p5mr /
X41-2026-002
Target audience: operators of self-hosted and local LLM infrastructure.
A single character injected into the HTTP Host header bypasses path-based authorization in Starlette, the routing core of FastAPI. Through FastAPI, this primitive (now tracked as CVE-2026-48710 and branded BadHost by the discoverers) reaches a large segment of the Python AI tooling ecosystem: vLLM (where the bug was discovered), LiteLLM, Text Generation Inference, most OpenAI-shim proxies, MCP servers, agent harnesses, eval dashboards, and model-management UIs. The exploit primitive is one character. The fix is Starlette 1.0.1, quietly released with a CVSS 6.5 Moderate score that materially understates the downstream impact. The discoverers themselves characterize the bug as critical.
A free online scanner for CVE-2026-48710 is available at badhost.org, run jointly by X41 D-Sec, Persistent Security Industries, and Bintech.
| CVE | CVE-2026-48710 (BadHost) |
| Downstream severity | Critical (per the discoverers) |
| Upstream severity, as scored | Moderate (CVSS 6.5) — understated |
| Exploitability | Trivial. One malformed header. |
| Auth required | None |
| Automatable | Yes. Suitable for mass scanning. |
| Discovered in | A source code audit of vLLM by X41 D-Sec |
| Online scanner | badhost.org |
| Patch | Starlette 1.0.1 (quietly released) |
| Affected | starlette >= 0.8.3, < 1.0.1 and everything that depends on it |
Known-impacted downstream stacks: FastAPI (the dominant downstream consumer of Starlette and the foundation of most modern Python web and AI services), LiteLLM proxy, vLLM (the project the bug was discovered against), Text Generation Inference and related wrappers, most "OpenAI-API-shim" projects fronting local model runners, a large number of MCP servers, agent harnesses, eval dashboards, model registries, and internal admin panels built on FastAPI.
Starlette reconstructs request.url by concatenating the HTTP Host header with the request path and re-parsing the result. The Host value is not validated against the RFC 9112 / RFC 3986 grammar before reconstruction. A Host header containing /, ?, or # shifts the path, query, and fragment boundaries during re-parse, so request.url.path no longer matches the path the ASGI server actually received and routed against.
The router dispatches on the real wire path. Middleware sees the poisoned, re-parsed path. Any path-based security decision made in middleware can be bypassed while the underlying route still executes.
Minimal proof of concept:
curl -i -H 'Host: foo' http://target/admin # 403, blocked
curl -i -H 'Host: foo?' http://target/admin # 200, served
The exploit primitive is one character.
The upstream Starlette advisory was published with a CVSS score of 6.5 (Moderate), characterizing the issue strictly at the library layer as a path string mismatch. The patch shipped quietly, without an accompanying ecosystem-wide warning. That framing materially understates the downstream impact. The discoverers, who actually examined what the primitive does to consumers of the library, characterize CVE-2026-48710 as critical.
This is a primitive, not an outcome. What it costs the ecosystem is determined by what downstream consumers do with request.url. X41's analysis found multiple popular open source projects whose middleware gates security-relevant decisions on request.url, with demonstrated chains from this single-character primitive to authentication bypass, SSRF, and remote code execution.
FastAPI is built on Starlette, and FastAPI is the base layer for the bulk of the Python AI plumbing deployed today. The transitive blast radius is not "a Python web framework"; it is most of the model-serving, gateway, proxy, eval, agent, and MCP-server infrastructure that has been stood up in the last two years.
Four points worth keeping in mind:
uvicorn (or hypercorn, daphne, granian) on internal networks, lab subnets, workstations, and bench hardware. The reverse-proxy mitigation that protects production websites is frequently absent in research, eval, and dev deployments.Where Starlette-based middleware (including FastAPI middleware) enforces authorization or routing restrictions using request.url or request.url.path, the following should be assumed reachable by an unauthenticated remote attacker:
/admin, /v1/models, /internal, /metrics, /shutdown, tool-execution endpoints)For LLM gateways specifically, the admin and key-management surface of services like LiteLLM, and the model and runtime control surface of services like vLLM, must be treated as exposed if the deployment is direct-to-ASGI.
The fastest way to test a reachable endpoint is the BadHost online scanner: badhost.org. For systematic review, you are likely exposed if any of the following are true:
uvicorn, hypercorn, daphne, or granian without an HTTP/1.1-compliant reverse proxy in front.request.url.path in any authentication, authorization, audit, rate-limiting, or routing-decision code.Upgrade Starlette to 1.0.1 or later. Rebuild and redeploy every container, virtualenv, and bundled artifact that pins or vendors Starlette. Bundled installs are common in LLM tooling; pip list on the host is not enough. Audit images.
request.url and request.url.path with request.scope["path"] in every middleware, dependency, and decorator that makes security decisions. Grep the codebase. This bug class will recur; reading the un-reconstructed value is the durable fix.Host headers in front of every ASGI-served application. nginx, Apache httpd, and Cloudflare reject the PoC by default. Verify your specific config.Host header handling explicitly with the X41 PoC before relying on the proxy as a mitigation.Three options, in order of effort:
Host header contains any of: /, ?, #, \, @. Legitimate clients do not emit these characters in Host.request.url.path your application recorded for that request. Any non-equal pair is the exploit signature.| 2026-01-27 | Issue identified during X41 source code audit of vLLM |
| 2026-02-04 | Starlette vendor notified, PoC supplied |
| 2026-02-05 | Vendor acknowledged |
| 2026-03-01 | Patch proposed by vendor |
| 2026-05-21 | Patch released (Starlette 1.0.1, scored CVSS 6.5 Moderate) |
| 2026-05-22 | Public disclosure, CVE-2026-48710 assigned, badhost.org launched |
Note: end-to-end the vendor was pushed for roughly four months before shipping, with the proposed patch sitting for nearly three of those months between proposal and release. The fix was released quietly, scored CVSS 6.5 Moderate at the library layer, with no ecosystem-wide notice corresponding to the actual downstream blast radius. Public disclosure and patch availability landed on the same day, so operators should assume zero exploit development lead time.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。