python.unbounded_cache
Stability
Medium
Causes Production Outages
Detects @lru_cache without maxsize parameter or @cache decorator (unbounded by default).
Why It Matters
Section titled “Why It Matters”Unbounded caches grow without limit:
- Memory exhaustion — Eventually causes OOM and crashes
- User-dependent keys — If cache keys come from user input, attackers can fill your memory
- Slow death — Memory grows gradually, then suddenly tips over
This is especially dangerous in long-running services where the cache accumulates over days or weeks.
Example
Section titled “Example”# ❌ Beforefrom functools import lru_cache
@lru_cachedef expensive_computation(x): return x * 2Without maxsize, this grows forever.
# ✅ Afterfrom functools import lru_cache
@lru_cache(maxsize=1000)def expensive_computation(x): return x * 2With maxsize, least-recently-used entries get evicted.
What Unfault Detects
Section titled “What Unfault Detects”@lru_cachewithout parentheses (no maxsize)@lru_cache()with empty parentheses (maxsize=128 default is often too small to catch)@cachedecorator (completely unbounded, Python 3.9+)@lru_cache(maxsize=None)(explicitly unbounded)
Auto-Fix
Section titled “Auto-Fix”Unfault can add maxsize=1000 to @lru_cache calls when the transformation is straightforward. Adjust the value based on your use case.
Best Practices
Section titled “Best Practices”# For functions with bounded input domain@lru_cache(maxsize=256)def get_config(env: str): return load_config(env) # env is limited set of values
# For functions with user input# Don't cache at all, or use TTL-based cachefrom cachetools import TTLCache
cache = TTLCache(maxsize=1000, ttl=300)