{"id":"CVE-2026-25478","aliases":["GHSA-2p2x-hpg8-cqp2","PYSEC-2026-2195"],"title":"Litestar's CORS origin allowlist has a bypass due to unescaped regex metacharacters in allowed origins","summary":"Litestar's CORS origin allowlist has a bypass due to unescaped regex metacharacters in allowed origins","severity":"high","cvss":7.4,"cvssVector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N","vendor":"litestar","product":"litestar","ecosystem":"pip","affected":["litestar >= 2.19.0, < 2.20.0"],"patched":["litestar 2.20.0"],"published":"2026-02-09","updated":"2026-07-13","source":"OSV","sourceUrl":"https://osv.dev/vulnerability/GHSA-2p2x-hpg8-cqp2","references":[{"url":"https://github.com/litestar-org/litestar/security/advisories/GHSA-2p2x-hpg8-cqp2"},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-25478"},{"url":"https://github.com/litestar-org/litestar/commit/eb87703b309efcc0d1b087dcb12784e76b003d5a"},{"url":"https://docs.litestar.dev/2/release-notes/changelog.html#2.20.0"},{"url":"https://github.com/litestar-org/litestar"},{"url":"https://github.com/litestar-org/litestar/releases/tag/v2.20.0"}],"tags":["osv","pip"],"epss":0.00398,"epssPercentile":0.338,"ingestedAt":"2026-07-13T18:57:51.359Z","slug":"CVE-2026-25478","body":"## Overview\n\n### 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() -> 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) -> 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 → no ACAO\nOrigin: https://goodXexample → 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’s browser session.\n\n## Affected packages\n\n- `litestar >= 2.19.0, < 2.20.0`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `litestar 2.20.0`","depth":"twilight","depthScore":41,"depthScoreParts":{"impact":40.7,"likelihood":0.1,"exploitation":0,"ransomware":0},"changes":[]}