Jun 4, 2026·7 min read·134 visits
A validation flaw in Starlette's Host header parsing enables attackers to bypass security middleware checks. By adding characters like '?' or '#' to the Host header, the framework miscalculates the request path as '/' (public) while the router still executes the actual targeted administrative endpoint.
CVE-2026-48710 is a critical security-desynchronization vulnerability in the Starlette ASGI framework (versions >= 0.8.3, < 1.0.1) that allows remote attackers to bypass path-based security middleware and access-control decorators. By injecting URI authority-to-path delimiters into the Host header, attackers can manipulate the application-level parsed URL path while the underlying ASGI server dispatches the request to target endpoints.
The Starlette Asynchronous Server Gateway Interface (ASGI) framework is a foundational toolkit for high-performance Python web applications. It serves as the primary engine for FastAPI, LiteLLM, vLLM, and numerous Model Context Protocol (MCP) server implementations. The framework's architecture depends on parsing and reconstructing incoming HTTP requests to expose unified request attributes, including request.url and request.url.path, to application-level logic.
Path-based security middleware and decorators routinely inspect request.url.path to enforce authentication, authorization, and tenant isolation policies. If an application restricts access to paths like /admin or /metrics, the middleware verifies the incoming path against these specific routes before routing. This architecture assumes that the path analyzed by the middleware is identical to the path evaluated by the downstream router.
CVE-2026-48710 exposes a design flaw where this assumption fails. The framework fails to validate the characters within the client-controlled Host HTTP header before constructing the absolute URL object. This oversight allows attackers to inject URL authority-to-path delimiters, causing a parser differential between the application's security middleware and its internal routing engine.
The vulnerability is classified under CWE-444 (Inconsistent Interpretation of HTTP Requests), CWE-1289 (Improper Validation of Unsafe Equivalence in Input), and CWE-436 (Inconsistent Interpretation of HTTP Requests). It represents a critical architectural vulnerability because it bypasses centralized security controls without requiring credentials or complex multi-stage payloads.
The root cause of CVE-2026-48710 resides in starlette/datastructures.py during the reconstruction of the client's absolute request URL. To build the URL object, Starlette reads the incoming request headers to extract the Host value. It then concatenates this raw, unvalidated Host header string with the ASGI scheme and the raw request path extracted from the ASGI scope.
The concatenation is performed using a basic format string: url = f"{scheme}://{host_header}{path}". The resulting string is subsequently passed to Python's standard urllib.parse.urlsplit function to instantiate the parsed URL object. Under RFC 3986, a valid Host header represents the authority and must only contain valid hostname characters, dots, colons, and digits for port specification.
When an attacker provides a malformed Host header containing URL authority-to-path delimiters (such as /, ?, or #), the standard Python URL parser is desynchronized. For example, if the Host header is target.com? and the request path is /admin, the concatenated string becomes http://target.com?/admin. The urlsplit function interprets the ? character as the beginning of the query string. Consequently, it parses the authority (netloc) as target.com, the path as /, and the query string as /admin.
This structural misinterpretation creates a parser differential. The security middleware queries request.url.path and receives /, concluding that the request is targeting the public root directory. Concurrently, the ASGI router routes the request based on the unmanipulated, raw ASGI scope['path'], which remains /admin. This dual-interpretation pipeline allows unauthorized requests to reach gated endpoints.
An examination of the vulnerable code in starlette/datastructures.py highlights the absence of validation prior to URL construction:
# Vulnerable URL construction in starlette/datastructures.py
host_header = None
for key, value in scope.get("headers", []):
if key == b"host":
host_header = value.decode("latin-1")
break
if host_header is not None:
# Raw concatenation allowing arbitrary injection in the host_header string
url = f"{scheme}://{host_header}{path}"
elif server is None:
url = pathThe official security patch introduced in commit 764dab0dcfb9033d75442d7a359645c9f94648c6 mitigates this flaw by implementing a strict regular expression validation step. The validation regex ensures that only RFC-compliant characters are present in the Host header before any concatenation takes place:
# Patched implementation in starlette/datastructures.py
import re
# Regex to reject Host header chars (/, ?, #, @, etc.) that modify urlsplit outcomes
_HOST_RE = re.compile(r"^([a-z0-9.-]+|\[[a-f0-9]*:[a-f0-9.:]+\])(?::[0-9]+)?$", re.IGNORECASE)
# ... inside URL class construction
if host_header is not None and _HOST_RE.fullmatch(host_header):
url = f"{scheme}://{host_header}{path}"
elif server is None:
url = pathIf the Host header contains characters that do not match the _HOST_RE pattern, the application discards the host_header and falls back to using the ASGI-provided server tuple. This ensures that the constructed request.url.path correctly reflects the actual request path, eliminating the logic desynchronization.
This fix is robust because it relies on strict allow-listing rather than block-listing. By restricting the permitted character set to standard domain characters, IPv4/IPv6 addresses, and optional numeric port suffixes, it structurally prevents any delimiter-injection attack variants.
Exploitation of CVE-2026-48710 requires no authentication and can be completed in a single HTTP request. The prerequisites are an application utilizing a vulnerable version of Starlette (or downstream FastAPI), and the deployment of path-based security middleware that evaluates access permissions using request.url.path rather than the raw ASGI scope['path'].
An attacker crafts an HTTP request where the target endpoint is specified in the request line, but the Host header is modified to include a trailing delimiter character. The following text-based sequence diagram illustrates the flow of the attack:
When sending the payload GET /admin HTTP/1.1 with Host: target.com?, the ASGI server populates the routing table with /admin. The Starlette middleware intercepts this request, reconstructs the URL as http://target.com?/admin, and parses the path as /. The middleware permits the request because / is configured as a public path. The request is then dispatched to the /admin handler, which executes and returns the privileged response.
Alternative delimiters such as # or / can also be exploited depending on the specific reverse-proxy or ASGI server configuration. Security scanners can detect this by validating the response differences between standard queries and modified Host header queries.
The impact of CVE-2026-48710 is critical for multi-tenant systems, administrative interfaces, and AI/LLM deployment pipelines. Because Starlette is the foundational dependency of FastAPI, any FastAPI application employing path-based authentication middleware is vulnerable to complete authentication bypass.
In modern Large Language Model (LLM) infrastructures using vLLM or LiteLLM, administrative endpoints often manage model loading, hardware allocation, prompt configurations, and tool execution. Bypassing access controls on these endpoints allows remote attackers to execute arbitrary system evaluations, modify models, or extract sensitive datasets.
This vulnerability has been assigned a CVSS v4.0 Base Score of 7.0 (High Severity) with the vector CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:N/SC:H/SI:H/SA:N. The CVSS v3.1 rating is 6.5 (Medium Severity). While the base severity is high, the absolute risk depends on whether the application relies on path-based middleware for security boundaries.
Because Starlette is embedded deep within downstream packages, many organizations are unaware that their running containers house the vulnerable parsing logic. The exploit requires minimal technical complexity, and public scanner scripts are already weaponized, increasing the likelihood of targeted scanning.
The primary remediation strategy is upgrading the Starlette library to version 1.0.1 or higher. For downstream applications like FastAPI, ensuring that Starlette is updated in the application's environment is sufficient, as FastAPI inherits Starlette's request-handling components.
For environments where library upgrades are delayed due to legacy dependency pinning, developers should modify custom middleware to read the raw, unmanipulated ASGI path directly instead of using the constructed URL path. Replacing request.url.path with request.scope["path"] in authorization checks ensures that the middleware evaluates the exact path that the router will ultimately execute.
Deploying a reverse proxy or Web Application Firewall (WAF) in front of the ASGI application provides immediate perimeter protection. Standard configurations in Nginx, Cloudflare, or AWS Application Load Balancers (ALB) naturally reject invalid characters within the Host header and terminate the connection before it reaches the Python application server.
Organizations should configure network-level ingress filters to ensure that direct access to the ASGI server (e.g., Uvicorn or Hypercorn) is blocked from external networks. ASGI servers should only bind to the local loopback interface (127.0.0.1), forcing all external traffic to pass through a sanitizing reverse proxy.
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:N/SC:H/SI:H/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Starlette Encode | >= 0.8.3, < 1.0.1 | 1.0.1 |
FastAPI Tiangolo | <= 0.115.x | Dependent on Starlette 1.0.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-1289 |
| Attack Vector | Network (AV:N) |
| CVSS v4.0 Score | 7.0 (High Severity) |
| EPSS Score | 0.00353 (0.35%) |
| Impact | Authentication and Authorization Bypass |
| Exploit Status | Proof-of-Concept (PoC) public, scanner code weaponized |
| KEV Status | Not listed |
The application does not properly validate or normalize inputs, leading to inconsistent interpretations of equivalent paths or identifiers.
A stored Cross-Site Scripting (XSS) vulnerability exists within plone.restapi, the REST API package for Plone content management system. By supplying a spoofed input MIME type (text/x-html-safe), an attacker can mislead the rendering layer (plone.app.textfield) into assuming that the supplied content is already sanitized. This causes the system to skip the safe_html transform, allowing arbitrary JavaScript to execute in the victim's browser when they view the compromised page.
An untrusted search path vulnerability in the GlobalDatabasePlugin component of the AWS Advanced JDBC Wrapper for Amazon Aurora PostgreSQL allows authenticated, low-privilege database users to hijack administrative session queries. By defining a custom function in a writable schema such as the public schema, an attacker can hijack queries executed automatically during driver-level topology detection. When a highly privileged database user connects to the database utilizing an affected version of the wrapper, the custom function executes under their security context, enabling remote privilege escalation to rds_superuser.
CVE-2026-27771 represents a critical security flaw in Gitea and Forgejo (up to and including version 1.26.1) involving missing authorization checks (CWE-862). Unauthenticated remote attackers can query, enumerate, and download private container images from the OCI-compliant container registry. Additionally, unauthorized users can retrieve private or internal source repository URLs via the Composer package registry metadata API. A public proof-of-concept exists, and threat metrics indicate highly active scanning and exploitation risks.
A missing authorization vulnerability in the Formie plugin for Craft CMS prior to version 3.1.28 allows low-privileged Control Panel users to read and modify sensitive administrative settings, configuration options, and third-party integrations.
CVE-2026-53598 is a directory traversal and arbitrary file read vulnerability in Microsoft Prompty ecosystem loaders across multiple languages. Prior to version 2.0.0-beta.2, the loaders resolved `${file:...}` reference strings inside frontmatter configuration blocks without enforcing that the target file paths resided within authorized directories. This deficiency allows an attacker-controlled configuration file to read sensitive operating system and application files through absolute paths, directory traversal, or symbolic link escapes. The issue is addressed across the Python, C#, Node.js/TypeScript, and Rust ecosystems.
A directory traversal vulnerability exists in the copy subcommand of the proot-distro utility. Due to incomplete path sanitization, local attackers or malicious scripts can read from or write to arbitrary files outside the container rootfs, bypassing isolation barriers and potentially gaining unauthorized access or persistent execution on the host system.