GHSA-2P2X-HPG8-CQP2

Vulnerability from github – Published: 2026-02-09 17:18 – Updated: 2026-02-09 22:38
VLAI?
Summary
Litestar's CORS origin allowlist has a bypass due to unescaped regex metacharacters in allowed origins
Details

Summary

CORS origin validation can be bypassed because the allowed-origins allowlist is compiled into a regex without escaping metacharacters (notably .). An allowed origin like https://good.example can match https://goodXexample, resulting in Access-Control-Allow-Origin being set for an untrusted origin

Details

CORSConfig.allowed_origins_regex is constructed using a regex built from configured allowlist values and used with fullmatch() for validation. Because metacharacters are not escaped, a malicious origin can match unexpectedly. The check relies on allowed_origins_regex.fullmatch(origin).

PoC

Server (poc_cors_server.py)

from litestar import Litestar, get
from litestar.config.cors import CORSConfig

@get("/c")
async def c() -> str:
    return "ok"

cors = CORSConfig(
    allow_origins=["https://good.example"],
    allow_credentials=True,
)
app = Litestar([c], cors_config=cors)

uvicorn poc_cors_server:app --host 127.0.0.1 --port 8002

Client (poc_cors_client.py)

import http.client

def req(origin: str) -> tuple[int, str | None]:
    c = http.client.HTTPConnection("127.0.0.1", 8002, timeout=3)
    c.request("GET", "/c", headers={"Origin": origin, "Host": "example.com"})
    r = c.getresponse()
    r.read()
    acao = r.getheader("Access-Control-Allow-Origin")
    c.close()
    return r.status, acao

print("evil:", req("https://evil.example"))
print("bypass:", req("https://goodXexample")) 

Expected (vulnerable behavior):

Origin: https://evil.example → no ACAO Origin: https://goodXexample → ACAO: https://goodxexample/ (bypass)

Impact

Type: CORS policy bypass (cross-origin data exposure risk) Who is impacted: apps using CORS allowlists to restrict browser cross-origin reads. If allow_credentials=True and authenticated endpoints return sensitive data, an attacker-controlled site can potentially read responses in a victim’s browser session.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "litestar"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.19.0"
            },
            {
              "fixed": "2.20.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ],
      "versions": [
        "2.19.0"
      ]
    }
  ],
  "aliases": [
    "CVE-2026-25478"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-942"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-02-09T17:18:52Z",
    "nvd_published_at": "2026-02-09T20:15:57Z",
    "severity": "HIGH"
  },
  "details": "### Summary\nCORS origin validation can be bypassed because the allowed-origins allowlist is compiled into a regex without escaping metacharacters (notably .). An allowed origin like https://good.example can match https://goodXexample, resulting in Access-Control-Allow-Origin being set for an untrusted origin\n\n### Details\nCORSConfig.allowed_origins_regex is constructed using a regex built from configured allowlist values and used with fullmatch() for validation. Because metacharacters are not escaped, a malicious origin can match unexpectedly. The check relies on allowed_origins_regex.fullmatch(origin).\n\n### PoC\nServer (poc_cors_server.py)\n\n```\nfrom litestar import Litestar, get\nfrom litestar.config.cors import CORSConfig\n\n@get(\"/c\")\nasync def c() -\u003e str:\n    return \"ok\"\n\ncors = CORSConfig(\n    allow_origins=[\"https://good.example\"],\n    allow_credentials=True,\n)\napp = Litestar([c], cors_config=cors)\n```\n\n`uvicorn poc_cors_server:app --host 127.0.0.1 --port 8002`\n\nClient (poc_cors_client.py)\n\n```\nimport http.client\n\ndef req(origin: str) -\u003e tuple[int, str | None]:\n    c = http.client.HTTPConnection(\"127.0.0.1\", 8002, timeout=3)\n    c.request(\"GET\", \"/c\", headers={\"Origin\": origin, \"Host\": \"example.com\"})\n    r = c.getresponse()\n    r.read()\n    acao = r.getheader(\"Access-Control-Allow-Origin\")\n    c.close()\n    return r.status, acao\n\nprint(\"evil:\", req(\"https://evil.example\"))\nprint(\"bypass:\", req(\"https://goodXexample\")) \n```\n\nExpected (vulnerable behavior):\n\nOrigin: https://evil.example \u2192 no ACAO\nOrigin: https://goodXexample \u2192 ACAO: https://goodxexample/ (bypass)\n\n### Impact\nType: CORS policy bypass (cross-origin data exposure risk)\nWho is impacted: apps using CORS allowlists to restrict browser cross-origin reads. If allow_credentials=True and authenticated endpoints return sensitive data, an attacker-controlled site can potentially read responses in a victim\u2019s browser session.",
  "id": "GHSA-2p2x-hpg8-cqp2",
  "modified": "2026-02-09T22:38:05Z",
  "published": "2026-02-09T17:18:52Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/litestar-org/litestar/security/advisories/GHSA-2p2x-hpg8-cqp2"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-25478"
    },
    {
      "type": "WEB",
      "url": "https://github.com/litestar-org/litestar/commit/eb87703b309efcc0d1b087dcb12784e76b003d5a"
    },
    {
      "type": "WEB",
      "url": "https://docs.litestar.dev/2/release-notes/changelog.html#2.20.0"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/litestar-org/litestar"
    },
    {
      "type": "WEB",
      "url": "https://github.com/litestar-org/litestar/releases/tag/v2.20.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Litestar\u0027s CORS origin allowlist has a bypass due to unescaped regex metacharacters in allowed origins"
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Sightings

Author Source Type Date

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.


Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…