Litestar has a CORS origin allowlist bypass due to unescaped regex metacharacters in allowed origins
Description
Litestar is an Asynchronous Server Gateway Interface (ASGI) framework. Prior to 2.20.0, 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). This vulnerability is fixed in 2.20.0.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
CVE-2026-25478 is a vulnerability in Litestar prior to 2.20.0 where the CORS allowed_origins regex fails to escape metacharacters, allowing a malicious origin to bypass validation.
Vulnerability
Overview
Litestar, an ASGI framework, prior to version 2.20.0 contains a CORS misconfiguration vulnerability in CORSConfig.allowed_origins_regex. The allowed_origins property is used to construct a regex pattern that is then matched using fullmatch(). However, because user-configured origin values are not escaped for regex metacharacters, an attacker can craft an origin string that unexpectedly matches the intended allowlist pattern [1][3]. For example, the changelog notes that a value like example.com could allow exampleX as well as example.com` [1].
Exploitation and
Attack Surface
This vulnerability is exploitable from any attacker-controlled website that can send cross-origin requests to a vulnerable Litestar application. No authentication is required to trigger the CORS validation. An attacker would need to craft an origin header containing metacharacters that cause the regex to match an allowed origin incorrectly. Since the regex is used with fullmatch(), the bypass requires careful crafting of the origin string to match the entire pattern, but the lack of escaping significantly broadens the possibilities [3].
Impact
Successful exploitation allows an attacker to bypass the intended CORS protections, enabling malicious cross-origin requests to be processed as legitimate. This could include accessing sensitive endpoints or performing actions on behalf of authenticated users if the application relies on CORS as a security boundary. The impact is elevated because CORS is a key browser-enforced security mechanism [2][3].
Mitigation
The vulnerability is fixed in Litestar version 2.20.0, released on 2026-02-08 [1][4]. Users are advised to upgrade immediately. As of this writing, no workarounds are documented, and the CVE is not listed on CISA's Known Exploited Vulnerabilities (KEV) catalog.
AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
litestarPyPI | >= 2.19.0, < 2.20.0 | 2.20.0 |
Affected products
2- Range: <2.20.0
- litestar-org/litestarv5Range: < 2.20.0
Patches
1eb87703b309efix(cors): Ensure allow_origins are properly escaped before constructing regex
2 files changed · +47 −3
litestar/config/cors.py+13 −3 modified@@ -1,9 +1,10 @@ from __future__ import annotations import re +import uuid from dataclasses import dataclass, field from functools import cached_property -from typing import TYPE_CHECKING, Literal, Pattern +from typing import TYPE_CHECKING, Final, Literal, Pattern from litestar.constants import DEFAULT_ALLOWED_CORS_HEADERS @@ -14,6 +15,11 @@ from litestar.types import Method +# this is just a UUID, so we can be sure it's not contained within the string we're +# calling '.replace' on +_RE_ESCAPE_PLACEHOLDER: Final = uuid.uuid4().hex + + @dataclass class CORSConfig: """Configuration for CORS (Cross-Origin Resource Sharing). @@ -59,10 +65,14 @@ def allowed_origins_regex(self) -> Pattern[str]: Returns: A compiled regex of the allowed path. """ - origins = self.allow_origins + # escape the allowed origins, while turning '*' into wildcard '.*' matches + origins = [ + re.escape(o.replace("*", _RE_ESCAPE_PLACEHOLDER)).replace(_RE_ESCAPE_PLACEHOLDER, ".*") + for o in self.allow_origins + ] if self.allow_origin_regex: origins.append(self.allow_origin_regex) - return re.compile("|".join([origin.replace("*.", r".*\.") for origin in origins])) + return re.compile("|".join(origins)) @cached_property def is_allow_all_origins(self) -> bool:
tests/unit/test_middleware/test_cors_middleware.py+34 −0 modified@@ -120,3 +120,37 @@ def handler() -> Dict[str, str]: assert response.headers.get("Access-Control-Allow-Origin") == origin else: assert not response.headers.get("Access-Control-Allow-Origin") + + +@pytest.mark.parametrize( + "allow_origin,origin,host,should_allow", + [ + ("httpx://good.example", "https://goodXexample", "example.com", False), + ("https://*good.example", "https://very.good.example", "very.good.example", True), + ("https://*good.example", "https://verygood.example", "vergood.example", True), + ("https://*good.example", "https://good.example", "good.example", True), + ("https://*good.example", "https://bad.example", "bad.example", False), + ("https://*.good.example", "https://very.good.example", "very.good.example", True), + ("https://*.good.example", "https://verygood.example", "verygood.example", False), + ("https://*.good.example", "https://some.verygood.example", "verygood.example", False), + ("https://*.good.example", "https://good.example", "good.example", False), + ], +) +def test_cors_test_regex_escape(allow_origin: str, origin: str, host: str, should_allow: bool) -> None: + @get("/") + async def handler() -> None: + return None + + with create_test_client( + [handler], + cors_config=CORSConfig( + allow_origins=[allow_origin], + allow_credentials=True, + ), + ) as client: + res = client.get("/", headers={"Origin": origin, "Host": host}) + + if should_allow: + assert "Access-Control-Allow-Origin" in res.headers + else: + assert "Access-Control-Allow-Origin" not in res.headers
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-2p2x-hpg8-cqp2ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-25478ghsaADVISORY
- docs.litestar.dev/2/release-notes/changelog.htmlghsax_refsource_MISCWEB
- github.com/litestar-org/litestar/commit/eb87703b309efcc0d1b087dcb12784e76b003d5aghsax_refsource_MISCWEB
- github.com/litestar-org/litestar/releases/tag/v2.20.0ghsax_refsource_MISCWEB
- github.com/litestar-org/litestar/security/advisories/GHSA-2p2x-hpg8-cqp2ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.