Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐍 PyPI

GHSA-vxqx-rh46-q2pg

MEDIUM

GHSA-vxqx-rh46-q2pg is a medium-severity (CVSS 6.5) CWE-176 vulnerability in litestar. O3 Security confirms whether GHSA-vxqx-rh46-q2pg is actually reachable in your code before you act, and blocks exploitation at runtime until you patch.

Litestar's FileStore key canonicalization collisions allow response cache mixup/poisoning (ASCII ord + Unicode NFKD)

Also known asCVE-2026-25480PYSEC-2026-2197
Published
Feb 9, 2026
Updated
Jul 13, 2026
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed

Blast Radius

1 pkg affected
🐍litestar

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.

Description

Summary

FileStore maps cache keys to filenames using Unicode NFKD normalization and ord() substitution without separators, creating key collisions. When FileStore is used as response-cache backend, an unauthenticated remote attacker can trigger cache key collisions via crafted paths, causing one URL to serve cached responses of another (cache poisoning/mixup)

Details

litestar.stores.file._safe_file_name() normalizes input with unicodedata.normalize("NFKD", name) and builds the filename by concatenating c if alphanumeric else str(ord(c)) (no delimiter). This transformation is not injective, e.g.:

  • "k-" and "k45" both become "k45" (because - ord('-') == 45)
  • "k/\n" becomes "k4710", colliding with "k4710"
  • "K" (Kelvin sign) normalizes to "K", colliding with "K"

When used in response caching, the default cache key includes request path and sorted query params, which are attacker-controlled.

PoC

import asyncio, tempfile
from litestar.stores.file import FileStore

async def main():
    d = tempfile.mkdtemp(prefix="ls_filestore_poc_")
    store = FileStore(d, create_directories=True)
    await store.__aenter__()

    # 1) ASCII ord-collision: "-" -> 45
    await store.set("k-", b"A")
    v = await store.get("k45")
    print("k-  ->", v)
    print("k45 ->", await store.get("k45"))
    if v == b"A":
        print("VULNERABLE: 'k-' collides with 'k45'")

    # 2) NFKD collision: Kelvin sign -> K
    await store.set("K", b"B")   # U+212A
    v2 = await store.get("K")
    print("K ->", await store.get("K"))
    print("K ->", v2)
    if v2 == b"B":
        print("VULNERABLE: 'K' collides with 'K' (NFKD)")

if __name__ == "__main__":
    asyncio.run(main())

Impact

Vulnerability type: cache poisoning / cache key collision. Impacted deployments: applications using Litestar response caching with FileStore backend (or any attacker-influenced keying into FileStore). Possible impact: serving incorrect cached content across distinct URLs, potential confidentiality/integrity issues depending on what endpoints are cached.

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐍PyPIlitestar2.19.0&&< 2.20.02.20.0

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for litestar. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.

  2. Fix

    Update litestar to 2.20.0 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-vxqx-rh46-q2pg is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 pinpoints whether GHSA-vxqx-rh46-q2pg is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.

Tailored to GHSA-vxqx-rh46-q2pg. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

### Summary FileStore maps cache keys to filenames using Unicode NFKD normalization and ord() substitution without separators, creating key collisions. When FileStore is used as response-cache backend, an unauthenticated remote attacker can trigger cache key collisions via crafted paths, causing one URL to serve cached responses of another (cache poisoning/mixup) ### Details litestar.stores.file._safe_file_name() normalizes input with unicodedata.normalize("NFKD", name) and builds the filename by concatenating c if alphanumeric else str(ord(c)) (no delimiter). This transformation is not injec
O3 Security · Impact-Aware SCA

Is GHSA-vxqx-rh46-q2pg in your dependencies?

O3 detects GHSA-vxqx-rh46-q2pg across PyPI dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.