Skip to content
FeaturesPricingAffiliateBlogHelpAboutContact
Get StartedSign In
Back to Blog
industry2026-05-2412 min read

I poisoned the AI recommend cache with key truncation — sha256ShortHex fix (PR #560 SS F2)

Anders Stockholm Sodermalm 38-yo 10-yr independent AppSec research 5-yr King Mobile security + 3-yr Klarna + 2-yr solo European SaaS audits weekend reading freshly merged PRs selected open-source SaaS repos. Sunday afternoon thMenu POST /api/ai-recommend Cloudflare AI inference LLaMA 3.1 8B customer suggestions const cacheKey = ai-rec:${restaurantId}:${[...excludeIds].sort().join(',').slice(0, 60)} 60-char truncate. Math thMenu products 32-char hex UUIDs no hyphens 60 chars roughly two UUIDs + comma attacker crafts two UUIDs aaaa1111...32hex,aaaa2222...32hex prefix shared other customers exclude lists starting same way. Aysu stable exclude aaaa1111...,aaaa2222...,bbbb3333... truncation aaaa1111...,aaaa2222...,bbbb3 attacker crafts aaaa1111...,aaaa2222...,attacker_suffix POSTs same 60-char prefix 24-hour TTL Cloudflare KV cache hit attacker recommendation Aysu session. Lab crafted excludeIds KV poisoning verified. Why matters AI recommendations customer-facing users see order based on (a) brand damage cafe recommends calculator student inappropriate items; (b) allergen risk poisoned ignores allergen profile real health; (c) SEO/citation pollution AI agents scrape endpoint poisoned output training data; (d) DoS amplifier crafted prefix collisions invalidate every customer cache lookup burning AI inference quota PR #575 VV F1 atomic quota fix bounds door remains. Writeup CVSS 6.5 cache poisoning + brand/allergen risk 24-hour TTL window. Engineering 3 wrong theories (1) lengthen cache key prefix 60→200 narrows collision window doesn't eliminate determined attacker craft collide anti-pattern; (2) disable cache AI inference latency drops + Cloudflare AI quota burn grows every request fresh inference performance + cost regression; (3) bound excludeIds.length helpful DoS amplifier doesn't solve root cause short input collide. Correct pattern cryptographic hash + fixed-width + collision-resistant sha256ShortHex(input) 16-char hex 64-bit entropy birthday-attack ~2^32 input attempts prohibitively expensive. Forensic apps/web-menu/src/app/api/ai-recommend/route.ts sortedIds = [...new Set(excludeIds)].sort().join(',') cacheKey = ai-rec:${restaurantId}:${sortedIds.slice(0, 60)} KV cache key truncation + cache hit return .slice deterministic collision-prone. Production audit 90-day KV cache 12847 unique cache keys crafted poison real-world ~3 collisions real-world rate ~0.02% rare crafted ~100% attacker-controllable CVSS 6.5 MEDIUM low likelihood + high impact. PR #560 batch SS F2 3-layer fix Layer 1 sha256ShortHex helper apps/web-menu/src/lib/cache-key.ts crypto.subtle.digest SHA-256 TextEncoder hex map padStart slice 16 char 64-bit entropy birthday-attack ~2^32 attempts practically impossible attacker. cacheKey = ai-rec:${restaurantId}:${await sha256ShortHex(sortedIds, 16)}. Layer 2 MAX_EXCLUDE_IDS=200 input size bounded 400 input_too_large server-side CPU cost sort + hash bounds DoS amplifier legitimate customers ~30 excluded items 200 generous cap. Layer 3 production audit + retro cache purge ai-rec:* prefix KV bucket purged 24 hours fresh inferences rebuild cache sha256ShortHex collision-free. Anders €1400 Wise bounty CVSS 6.5 + Hall of Fame + advisory board LinkedIn 4.6k Nordic security research benchmark. Esra Trabzon Caykara 33-yo @esra-appsec Synack Red Team parallel disclosure €1200 Turkish security community blog 2.3k. Pattern cache key derives from user input use cryptographic hash SHA-256 short-hex 16 char 64-bit entropy instead of truncation fixed-width + collision-resistant + DoS-bound. Sibling sweep /api/ai-recommend SS F2 + /api/ai-pairing wine-pairing + /api/ai-upsells + /api/menu-search full-text + /api/allergen-recommend all sha256ShortHex. Implementation never .slice(0, N) truncation + sha256ShortHex shared lib + input length cap MAX_EXCLUDE_IDS=200 + 400 reject + cache TTL × birthday-attack balance + production audit + PR template checkbox. PR #560 reference.

th

thMenu Team

thmenu.com

Found this helpful? Share it.