CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-25480

The Kelvin Collision: Breaking Litestar's Cache with Basic Arithmetic

Alon Barad
Alon Barad
Software Engineer

Feb 9, 2026·5 min read·17 visits

Executive Summary (TL;DR)

Litestar's file-based caching mechanism used a lossy string replacement method to generate filenames from keys. It replaced special characters with their ASCII decimal values (e.g., '-' becomes '45') without separators. This allows attackers to craft URLs that resolve to the same cache file as legitimate URLs, leading to cache poisoning.

A critical flaw in Litestar's FileStore component allows remote attackers to poison the server-side cache by exploiting a naive filename sanitization algorithm. By crafting specific request paths containing non-alphanumeric characters or Unicode anomalies (like the Kelvin sign), an attacker can force a filename collision on the disk, overwriting legitimate cache entries with malicious content.

The Hook: When "Safe" Isn't Safe

Caching is one of the two hardest problems in computer science (alongside naming things and off-by-one errors). When you build a web framework like Litestar, you eventually need to persist cached responses to disk. But filesystems are picky. You can't just take a raw URL like https://api.com/users/foo?query=bar and name a file that. The OS will scream at you about slashes, question marks, and length limits.

So, the developers implemented a helper function called _safe_file_name in the FileStore component. Its job was simple: take a dirty cache key and scrub it until it was shiny, alphanumeric, and safe for the filesystem. Ideally, this transformation should be injective—meaning every unique key produces a unique filename. If it doesn't, you get collisions. And in the world of caching, collisions mean you start serving User A's bank balance to User B.

Litestar didn't just have a collision; they had a predictable, calculable, and easily exploitable collision mechanism. It turns out that trying to invent your own encoding scheme using ASCII arithmetic instead of just using a standard hash function is a recipe for disaster. This vulnerability essentially turns the FileStore into a hash map where the attacker controls the bucket collisions.

The Logic Flaw: Arithmetic Without Delimiters

The vulnerability lies in how _safe_file_name sanitized strings. The logic was twofold. First, it normalized Unicode characters using NFKD form. This is generally good practice to handle things like accents, but it has side effects. For example, the Kelvin sign (K, U+212A) normalizes to the letter K. This means a key containing the Kelvin sign and a key containing a capital 'K' are treated as identical before they even hit the disk.

But the real horror show was the second step. The code iterated through the string and kept alphanumeric characters as-is. If a character wasn't alphanumeric, it replaced it with the string representation of its ASCII ordinal value (ord(c)). Crucially, it did this without delimiters.

Let's do the math. The hyphen character (-) has an ASCII value of 45. If your key is data-set, the function converts - to 45 and concatenates it. The result is data45set. Now, consider a legitimate key named data45set. The function sees that 4 and 5 are alphanumeric, so it keeps them. The result? data45set. Two completely different inputs resolve to the exact same filename. This isn't a rare hash collision; it's a structural guarantee.

The Code: Anatomy of a Collision

Here is the vulnerable implementation found in litestar/stores/file.py prior to version 2.20.0. It's a textbook example of "clever" code going wrong.

# The Vulnerable Implementation
import unicodedata
 
def _safe_file_name(name: str) -> str:
    # Step 1: Normalize (Kelvin sign becomes K)
    name = unicodedata.normalize("NFKD", name)
    
    # Step 2: The fatal flaw
    # No separators between the original chars and the ord() values
    return "".join(c if c.isalnum() else str(ord(c)) for c in name)

If we run this code with a few examples, the problem becomes obvious:

# legitimate_key usually maps to a resource ID like 45
key_legit = "user45"
# malicious_key uses a hyphen (ord 45) to mimic the ID
key_malicious = "user-"
 
print(_safe_file_name(key_legit))      # Output: user45
print(_safe_file_name(key_malicious))  # Output: user45

Because the FileStore uses this output directly as the filename to write data to, writing to user- overwrites user45. The system cannot distinguish between the two.

The Exploit: Cache Poisoning Made Easy

To exploit this, an attacker doesn't need authentication; they just need the target application to use ResponseCacheMiddleware with a FileStore backend. The goal is to poison the cache for a victim URL.

The Scenario: Imagine an endpoint /api/news/45 that serves a specific news article. The attacker wants to replace this content with their own payload (perhaps a defacement or a malicious redirect).

The Attack Chain:

  1. Reconnaissance: The attacker identifies that /api/news/45 is cached. They deduce the ID 45 corresponds to the ASCII character - (hyphen).
  2. Payload Delivery: The attacker sends a request to /api/news/-. This might seem like an invalid ID, but if the application logic simply reflects the input or returns a generic "Not Found" that gets cached, the damage is done.
  3. The Collision: Litestar computes the cache key for /api/news/-. The _safe_file_name function converts - to 45. It writes the response for the invalid request to the file .../api_news_45.
  4. The Victim: A legitimate user requests /api/news/45. Litestar computes the key, looks for .../api_news_45, finds the file created by the attacker, and serves it.

If the application caches 404s or error messages, the attacker effectively performs a Denial of Service by permanently caching an error page for a valid resource.

The Fix: Stop Being Clever, Start Hashing

The fix provided by the Litestar team in version 2.20.0 is straightforward and correct: abandon the custom string sanitization logic entirely. Instead of trying to preserve the readability of the filename, they switched to a cryptographic hash.

Hashing guarantees a fixed-length, filesystem-safe string (hex digest) and, for all practical purposes, eliminates collisions. Here is the patched code:

# The Fixed Implementation
import hashlib
 
def _safe_file_name(name: str) -> str:
    # BLAKE2s is fast and secure enough for this purpose
    return hashlib.blake2s(name.encode()).hexdigest()

This change ensures that user- becomes something like a1b2... and user45 becomes c3d4.... They no longer collide. The only downside is that looking at the cache directory manually is now cryptic, but that is a small price to pay for not serving random users each other's data.

Official Patches

LitestarGitHub Commit fixing the issue

Fix Analysis (1)

Technical Appendix

CVSS Score
6.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N

Affected Systems

Litestar Framework < 2.20.0 using FileStore

Affected Versions Detail

Product
Affected Versions
Fixed Version
Litestar
litestar-org
< 2.20.02.20.0
AttributeDetail
CWE IDCWE-178
Attack VectorNetwork
CVSS Score6.5
ImpactCache Poisoning
Exploit StatusProof of Concept Available
KEV StatusNot Listed

MITRE ATT&CK Mapping

T1557Adversary-in-the-Middle
Credential Access
T1499Endpoint Denial of Service
Impact
CWE-178
Improper Handling of Case Sensitivity

Improper Handling of Case Sensitivity

Known Exploits & Detection

ManualLocal reproduction using Python script to demonstrate string collision.

Vulnerability Timeline

Patch Merged
2026-02-08
CVE Published
2026-02-09

References & Sources

  • [1]GHSA Advisory
  • [2]Litestar 2.20.0 Changelog

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 10 hours ago•CVE-2026-48861
2.1

CVE-2026-48861: HTTP Request Splitting and Smuggling via Method Parameter CRLF Injection in Elixir Mint

CVE-2026-48861 is a client-side HTTP request-line CRLF (Carriage Return Line Feed) injection vulnerability in the popular Elixir HTTP client library, Mint. The vulnerability permits HTTP Request Splitting and HTTP Request Smuggling when an application forwards untrusted, attacker-controlled inputs to Mint's HTTP client requests as either the HTTP request method or target. By embedding CRLF characters within these parameters, an attacker can terminate the request line prematurely, inject malicious headers, or pipeline entirely independent requests. These smuggled requests are then processed by upstream or downstream proxy servers as separate HTTP queries on the same TCP connection. While Mint version 1.7.0 introduced target validation to secure the request target, the HTTP request method parameter remained completely unvalidated. This flaw allows attackers to bypass routing filters, access restricted internal APIs, or poison HTTP caches under default configurations.

Amit Schendel
Amit Schendel
6 views•7 min read
•about 11 hours ago•CVE-2026-49753
6.3

CVE-2026-49753: HTTP Request/Response Smuggling via Inconsistent Content-Length Parsing in Elixir Mint Client

An Inconsistent Interpretation of HTTP Requests (HTTP Request/Response Smuggling) vulnerability in the Elixir Mint HTTP client allows attacker-controlled HTTP/1 servers to desynchronize response framing on shared connections due to over-lenient parsing of sign-prefixed Content-Length headers.

Amit Schendel
Amit Schendel
6 views•6 min read
•about 11 hours ago•CVE-2026-49754
8.2

CVE-2026-49754: Denial of Service via Unbounded HTTP/2 CONTINUATION Frame Accumulation in Elixir Mint

An allocation of resources without limits or throttling vulnerability in Elixir Mint allows an attacker-controlled HTTP/2 server to exhaust memory in a Mint client. The vulnerability is exploited by sending a HEADERS frame without the END_HEADERS flag followed by an infinite stream of CONTINUATION frames. Because the client lacks limits on the incoming header-block accumulator, the client continuously consumes memory until an out-of-memory crash occurs.

Amit Schendel
Amit Schendel
7 views•6 min read
•about 12 hours ago•CVE-2026-48596
2.1

CVE-2026-48596: Improper Neutralization of CRLF Sequences in Elixir Tesla Multipart HTTP Client

CVE-2026-48596 is an Improper Neutralization of CRLF Sequences in HTTP Headers (HTTP Request/Response Splitting, CWE-113) in the Elixir Tesla HTTP client. The flaw resides in how multipart content-type parameters are joined and serialized, enabling attackers to inject arbitrary headers or split HTTP requests when applications pass untrusted inputs to the parameters of multipart uploads.

Alon Barad
Alon Barad
5 views•6 min read
•about 12 hours ago•CVE-2026-48594
8.2

CVE-2026-48594: Decompression Bomb Denial of Service in Elixir Tesla HTTP Client

An improper handling of highly compressed data (decompression bomb) vulnerability exists in the Elixir Tesla HTTP client when utilizing response decompression middlewares. By serving highly compressed responses or stacked content-encoding headers, a malicious server can cause arbitrary heap exhaustion, leading to a denial of service (DoS) crash in the BEAM virtual machine.

Amit Schendel
Amit Schendel
6 views•6 min read
•about 13 hours ago•CVE-2026-48595
8.2

CVE-2026-48595: Cross-Origin Credential Leakage in Elixir Tesla Client via Case-Sensitive Redirect Filter Bypass

A high-severity security vulnerability in Elixir's Tesla HTTP client library (CVE-2026-48595) allows unauthenticated remote attackers to harvest sensitive credentials, including Authorization headers and cookies. The flaw resides in the 'Tesla.Middleware.FollowRedirects' component, which performs case-sensitive lookups when stripping credentials during cross-origin redirects. Because HTTP headers are case-insensitive by RFC specifications, standard canonical casing (e.g., 'Authorization') bypasses the lowercase-only blocklist, leaking tokens to untrusted external redirect destinations.

Alon Barad
Alon Barad
6 views•5 min read