Starlette CVE-2026-48710: BadHost Authentication Bypass

Suspected
Discovered May 26, 2026

Starlette CVE-2026-48710 (BadHost) is a Host-header URL reconstruction flaw fixed in Starlette 1.0.1. New OSTIF, X41, Tenable, and BadHost scanner sources clarify that the highest-risk deployments are FastAPI/Starlette/LLM services whose middleware makes security decisions from request.url.path.

0
Affected Packages
0
Observables
4
Sources

Defender Action Panel

Triage this incident quickly

Check whether your environment installed affected software, copy the top IOCs, run the tested hunting script when available, then review remediation guidance.

Am I affected?
Review affected software below
Immediate action
Audit locks, CI runners, developer workstations, and credential exposure.
Hunting
Has hunting script

Analysis

Executive Summary

A critical authentication bypass vulnerability, designated CVE-2026-48710 and nicknamed "BadHost", has been disclosed in the Starlette web framework. New primary sources now clarify the exploit condition: Starlette versions before 1.0.1 reconstruct request.url from the raw HTTP Host header, while routing still uses the real ASGI path. Middleware that authorizes based on request.url.path can therefore see an attacker-controlled path that differs from the route actually executed OSTIF opens in a new tab Tenable opens in a new tab.

The highest-risk deployments are not every Starlette application equally. Prioritize FastAPI, Starlette, vLLM, LiteLLM, MCP gateways, OpenAI-compatible proxies, and internal AI/agent services that run directly on ASGI servers or use middleware to gate /admin, /v1/models, /mcp, /internal, /metrics, or tool-execution endpoints BadHost opens in a new tab OSTIF opens in a new tab. This article provides an impact determination and a Python audit script to identify vulnerable dependencies and Host-header exploit attempts.

Key Facts

Cve: CVE-2026-48710

Alias: BadHost

Vendor: Starlette

Product: Starlette (ASGI toolkit)

Disclosed Date: 2026-05-26

Vulnerability: Authentication bypass via Host header URL reconstruction injection

Cwe:

  • CWE-346
  • CWE-284

Affected Products:

  • Starlette
  • FastAPI applications with affected middleware
  • vLLM/LiteLLM/MCP services using affected middleware

Affected Versions:

  • Starlette < 1.0.1

Fixed Versions:

  • 1.0.1

Nvd Cvss V31: 6.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N

Public Tools:

  • badhost.org scanner
  • X41 PoC / Semgrep / CodeQL rules

Exploitation Status: public PoC and scanner available; active exploitation not confirmed in reviewed primary sources

Kev Status: not listed in CISA KEV as of 2026-05-27 review

Evidence Assessment

  • confirmed: OSTIF says the issue was discovered during a vLLM audit managed by OSTIF and sponsored by Alpha-Omega, and describes the path mismatch between router dispatch and middleware-visible request.url.path OSTIF opens in a new tab.
  • confirmed: Tenable's CVE entry states that Starlette before 1.0.1 did not validate the HTTP Host request header before reconstructing request.url; it lists the 1.0.1 fix behavior and references the GHSA, X41 advisory, Starlette commit, and BadHost scanner Tenable opens in a new tab.
  • confirmed: BadHost.org provides a public scanner and explains the exact bypass primitive, including Host: example.com/health?x= making request.url.path resolve to /health while the real request path reaches /protected BadHost opens in a new tab.
  • likely: Direct-to-ASGI AI and MCP services are disproportionately exposed because many deployments put path-based API-key or admin gating in middleware.
  • unclear: Reviewed primary sources do not prove active exploitation in the wild; treat public scanner/PoC availability as exposure pressure, not confirmed exploitation.

Impact Determination

Analysis table
ClassificationCriteriaRequired evidenceRemediation triggerClosure condition
Confirmed compromiseWeb/WAF logs show HTTP requests with path-delimiter characters (e.g. /, ?, #) in the Host header, followed by unauthorized access to administrative or restricted paths.Logs showing Host header values like example.com/health?x= targeting /admin with 200 OK status.Revoke all session keys, isolate internal API services, and run backend audits.Upgrade Starlette to 1.0.1 or later and verify backend logs for no further anomalous Host headers.
Presumed exposedThe web application is built on FastAPI or Starlette with version < 1.0.1, exposing path-based middleware authorization gates.requirements.txt or poetry.lock lockfile showing starlette < 1.0.1 in active production environments.Upgrade the library dependency immediately to a patched release.Dependency verification outputs showing starlette >= 1.0.1 installed.
Potentially exposedA Python project is running but lockfiles or backend web log records are not audited.Asset register indicating Python-based ASGI servers (FastAPI/Uvicorn) without version check.Execute the dependency and log audit script.Confirm if the asset is confirmed compromised, presumed exposed, or not exposed.
Not exposedThe system utilizes non-affected framework stacks, or Starlette version is verified >= 1.0.1.Verified dependency files showing version 1.0.1 or later.None for this CVE.Version verification bundle is archived.

Timeline

  • 2026-05-21: Starlette 1.0.1 patch is available according to downstream tracking references Tenable opens in a new tab.
  • 2026-05-26: OSTIF publishes expanded BadHost disclosure because slow patch uptake and live vulnerable services raised ecosystem concerns OSTIF opens in a new tab.
  • 2026-05-26: Tenable publishes/updates its CVE record with references to X41, OSTIF, GHSA, PyPA advisory data, the Starlette patch commit, and BadHost.org Tenable opens in a new tab.
  • 2026-05-27: This article is refreshed to remove the unsupported KEV/active-exploitation framing and replace generic source links with exact primary and tracker references.

What Happened

Starlette handles URL reconstruction dynamically by concatenating the raw HTTP Host header with the request path to build a unified URI string. Because the Host header was not validated against standard RFC grammar, attackers could inject custom query delimiters (/health?x=) directly into the Host field:

  • The Request: GET /admin with Host: example.com/health?x=
  • The Reconstruction: Starlette builds the internal URL as http://example.com/health?x=/admin.
  • The Bypass: The underlying ASGI server processes the request path /admin, but Starlette's routing/auth middleware inspects the reconstructed request.url.path which returns /health. If /health is whitelisted, the authentication check is bypassed entirely, granting unauthenticated access to the restricted /admin resources.

Technical Analysis

The fundamental error occurs during URL parsing inside Starlette's utility functions. By failing to validate that the host contains only valid hostname characters, re-parsing the reconstructed URL causes the injection parameters to overwrite the target path, shifting the path boundary forward. [1]

Affected Assets and Blast Radius

Asset Selectors:

  • starlette
  • fastapi
  • litellm
  • vllm

Highest Value Assets:

  • Internet-facing FastAPI applications utilizing path-based middleware
  • vLLM or LiteLLM AI endpoints exposed with API key authentication
  • Internal corporate admin dashboards written in Python ASGI frameworks

Credentials And Data At Risk:

  • Internal LLM access and model weights (via vLLM/LiteLLM bypass)
  • Backend database records accessible through administrative endpoints
  • Administrative session credentials and user data

Indicators of Compromise

The following indicators of compromise (IOCs) can be used to scope exposure across local repositories, systems, and telemetry exports:

Containment & Mitigation

  1. Host Header Validation: Ensure that front-facing reverse proxies (like Nginx, Apache, Caddy, Traefik, HAProxy, or Cloudflare) are explicitly configured to validate and normalize the Host header before passing the request downstream to Uvicorn/Starlette.
  2. Block Redirections: Add WAF rules to drop any incoming requests where the Host header contains non-standard URI characters such as /, ?, or #.

Eradication & Recovery

  1. Upgrade Starlette Dependency: Mandate immediate dependency upgrades of Starlette to version 1.0.1 or later:
    • Command: pip install --upgrade starlette or poetry update starlette
  2. Rotate Exposed Secrets: If web logs show successful requests (200 OK) featuring a poisoned Host header targeting restricted administration directories, immediately revoke and rotate all backend API keys and session credentials accessible through the compromised services.

Timeline

4 of 4 rows

Timeline
DateEventDescriptionSource
May 26, 2026First seenFirst seen recorded for Starlette CVE-2026-48710: BadHost Authentication Bypass.ostif.org
May 26, 2026DiscoveryDiscovery recorded for Starlette CVE-2026-48710: BadHost Authentication Bypass.ostif.org
May 26, 2026DisclosureDisclosure recorded for Starlette CVE-2026-48710: BadHost Authentication Bypass.ostif.org
May 26, 2026Starlette CVE-2026-48710: BadHost Authentication BypassUnknownostif.org

Affected Software

0 of 0 rows

Affected Software
PackageEcosystemVersion RangeStatusConfidenceSource
No rows match the active filters.

Tested Hunting Scripts

1 of 1 rows

Tested Hunting Scripts
TitleLanguageDescriptionRepositorySource
local repository and exported telemetry scopePythonDoes the telemetry scope contain patterns associated with Starlette CVE-2026-48710: BadHost Authentication Bypass?scripts/local_repository_and_exported_telemetry_scope.py opens in a new tabostif.org

Hunt Manifest: local repository and exported telemetry scope

Title
local repository and exported telemetry scope
Question
Does the telemetry scope contain patterns associated with Starlette CVE-2026-48710: BadHost Authentication Bypass?
Telemetry Family
Python
Repository
scripts/local_repository_and_exported_telemetry_scope.py
Show tested hunting scriptscripts/local_repository_and_exported_telemetry_scope.py
scripts/local_repository_and_exported_telemetry_scope.py opens in a new tabPython
#!/usr/bin/env python3
import os
import sys
from pathlib import Path

ROOT = sys.argv[1] if len(sys.argv) > 1 else "."
LOG_ROOT = os.environ.get("LOG_ROOT", "")
OUT = Path(os.environ.get("OUT", "hp-starlette-cve-2026-48710-badhost-scope"))


# Collect unique indicators
indicators = set()
for group in []:
    for val in group:
        if val:
            indicators.add(val)

with open(indicators_file, "w") as f:
    for ind in sorted(indicators):
        f.write(ind + "\n")

print(f"[+] Written unique selectors to {indicators_file}")

# Walk local directory
print(f"[+] Scanning directory: {ROOT} for selectors...")
matches = []
exclude_dirs = {"node_modules", "vendor", "dist", ".git"}
for root, dirs, filenames in os.walk(ROOT):
    dirs[:] = [d for d in dirs if d not in exclude_dirs]
    for filename in filenames:
        filepath = Path(root) / filename
        try:
            content = filepath.read_text(errors="ignore")
            for ind in indicators:
                if ind in content:
                    matches.append(f"{filepath}: found '{ind}'")
        except Exception:
            pass  # pass # return or raise not needed here  # pass # return or raise not needed here  # pass # return or raise not needed here

if matches:
    (OUT / "repository-indicator-matches.txt").write_text("\n".join(matches) + "\n")
    print(f"[!] Found {len(matches)} matches in codebase!")

# Optional Log Scanning
if LOG_ROOT and os.path.exists(LOG_ROOT):
    print(f"[+] Scanning telemetry log directory: {LOG_ROOT}...")
    log_matches = []
    for root, _, filenames in os.walk(LOG_ROOT):
        for filename in filenames:
            filepath = Path(root) / filename
            try:
                content = filepath.read_text(errors="ignore")
                for ind in indicators:
                    if ind in content:
                        log_matches.append(f"{filepath}: found '{ind}'")
            except Exception:
                pass  # pass # return or raise not needed here  # pass # return or raise not needed here  # pass # return or raise not needed here
    if log_matches:
        (OUT / "exported-telemetry-indicator-matches.txt").write_text("\n".join(log_matches) + "\n")
        print(f"[!] Found {len(log_matches)} matches in logs!")

    if PACKAGES:
        registry_dir = OUT / "registry"
        registry_dir.mkdir(exist_ok=True)

print(f"[+] Wrote scope artifacts under {OUT}")

Provenance & Sources

4 of 4 rows

Provenance & Sources
SourceTypeReliabilityClaimsEvidence
ostif.orgSecurity Researcher95%1Starlette CVE-2026-48710 (BadHost) is a Host-header URL reconstruction flaw fixed in Starlette 1.0.1. New OSTIF, X41, Tenable, and BadHost scanner sources clarify that the highest-risk deployments are FastAPI/Starlette/LLM services whose middleware makes security decisions from request.url.path.
tenable.comSecurity Researcher95%1Starlette CVE-2026-48710 (BadHost) is a Host-header URL reconstruction flaw fixed in Starlette 1.0.1. New OSTIF, X41, Tenable, and BadHost scanner sources clarify that the highest-risk deployments are FastAPI/Starlette/LLM services whose middleware makes security decisions from request.url.path.
GitHubSecurity Researcher95%2Starlette CVE-2026-48710 (BadHost) is a Host-header URL reconstruction flaw fixed in Starlette 1.0.1. New OSTIF, X41, Tenable, and BadHost scanner sources clarify that the highest-risk deployments are FastAPI/Starlette/LLM services whose middleware makes security decisions from request.url.path.
badhost.orgSecurity Researcher95%1Starlette CVE-2026-48710 (BadHost) is a Host-header URL reconstruction flaw fixed in Starlette 1.0.1. New OSTIF, X41, Tenable, and BadHost scanner sources clarify that the highest-risk deployments are FastAPI/Starlette/LLM services whose middleware makes security decisions from request.url.path.