Cache invalidation strategy implemented
Why it matters
A cache with no invalidation strategy serves stale data indefinitely. After a server-side update — price change, policy revision, content correction — users continue seeing the cached version until they clear app data or reinstall. ISO 25010:2011 reliability.recoverability requires a defined freshness boundary. Beyond staleness, unbounded caches accumulate sensitive data (PII, session-specific content) that should have been evicted after use. GDPR Art. 32 expects that personal data is not retained beyond its necessary lifetime — a cache without TTL enforcement is a retention policy violation by omission.
Severity rationale
High because indefinitely-cached data can include stale PII or pricing that misleads users and may violate GDPR Art. 32 data minimization obligations.
Remediation
Wrap every cache entry with a timestamp and a TTL. Evict on read when the entry is expired, and run a periodic cleanup to prevent storage accumulation.
interface CacheEntry<T> { data: T; storedAt: number; ttl: number; }
export class Cache<T> {
private store = new Map<string, CacheEntry<T>>();
set(key: string, data: T, ttl = 5 * 60_000) {
this.store.set(key, { data, storedAt: Date.now(), ttl });
}
get(key: string): T | undefined {
const entry = this.store.get(key);
if (!entry) return undefined;
if (Date.now() - entry.storedAt > entry.ttl) {
this.store.delete(key);
return undefined;
}
return entry.data;
}
invalidate(key: string) { this.store.delete(key); }
}
// Always invalidate after a mutation:
await updateUser(id, data);
userCache.invalidate(`user_${id}`);
Set TTLs no higher than 86,400 seconds (24 hours). For data containing PII, use a tighter TTL (≤3,600 seconds) aligned with your data retention policy.
Detection
-
ID:
cache-invalidation -
Severity:
high -
What to look for: Examine cache implementation. Look for TTL (time-to-live), versioning, or event-based invalidation. Check that stale cache is cleared when updates occur.
-
Pass criteria: Count all cache-related storage operations. Cache has at least 1 documented invalidation strategy: TTL-based expiration (with a defined TTL of no more than 86400 seconds / 24 hours), manual invalidation on updates, or server-driven invalidation. At least 1 cache cleanup or expiration mechanism must exist.
-
Fail criteria: No cache invalidation found. Cached data could be served indefinitely even after it is updated remotely.
-
Skip (N/A) when: Never — cache invalidation is essential for data freshness.
-
Detail on fail:
"No cache invalidation strategy found. Cache persists indefinitely, so users may see stale data until they manually clear cache." -
Remediation: Implement TTL-based cache invalidation:
interface CacheEntry<T> { data: T; timestamp: number; ttl: number; // milliseconds } class Cache<T> { private store = new Map<string, CacheEntry<T>>(); async get(key: string, fetch: () => Promise<T>, ttl = 5 * 60 * 1000): Promise<T> { const entry = this.store.get(key); if (entry && Date.now() - entry.timestamp < entry.ttl) { // Cache hit and not expired return entry.data; } // Cache miss or expired, fetch fresh data const data = await fetch(); this.store.set(key, { data, timestamp: Date.now(), ttl, }); return data; } invalidate(key: string) { this.store.delete(key); } invalidateAll() { this.store.clear(); } } // Usage: const cache = new Cache<User>(); const user = await cache.get(`user_${id}`, () => fetchUser(id), 10 * 60 * 1000); // 10 min TTL // After updating user, invalidate cache await updateUser(id, data); cache.invalidate(`user_${id}`);
External references
- iso-25010:2011 · reliability.recoverability — Recoverability
- gdpr · Art. 32 — Security of processing
Taxons
History
- 2026-04-18·v1.0.0·Initial import from mobile-offline-storage·automated