Skip to content

python.unbounded_cache

Stability Medium Causes Production Outages

Detects @lru_cache without maxsize parameter or @cache decorator (unbounded by default).

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.

# ❌ Before
from functools import lru_cache
@lru_cache
def expensive_computation(x):
return x * 2

Without maxsize, this grows forever.

# ✅ After
from functools import lru_cache
@lru_cache(maxsize=1000)
def expensive_computation(x):
return x * 2

With maxsize, least-recently-used entries get evicted.

  • @lru_cache without parentheses (no maxsize)
  • @lru_cache() with empty parentheses (maxsize=128 default is often too small to catch)
  • @cache decorator (completely unbounded, Python 3.9+)
  • @lru_cache(maxsize=None) (explicitly unbounded)

Unfault can add maxsize=1000 to @lru_cache calls when the transformation is straightforward. Adjust the value based on your use case.

# 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 cache
from cachetools import TTLCache
cache = TTLCache(maxsize=1000, ttl=300)