Aanvallen op KV-cache en prompt-caching
Hoe KV-cache-poisoning, misbruik van prefix-caching, side channels via cache-timing en falende isolatie in multi-tenant-omgevingen aanvalsvectoren creëren in de serving-infrastructuur van LLM's.
Overzicht
Key-Value-caching (KV-caching) is een fundamentele optimalisatie in transformer-gebaseerde LLM-inferentie. Tijdens autoregressieve generatie moet elk nieuw token attention besteden aan alle voorgaande tokens. Zonder caching betekent dit dat de key- en value-projecties voor elk eerder token bij elke generatiestap opnieuw moeten worden berekend — een O(n^2)-operatie die voor lange sequenties onbetaalbaar duur wordt. KV-caching slaat deze berekende key-value-paren op zodat ze maar één keer worden berekend, waardoor de generatie wordt teruggebracht tot O(n) per token.
Prompt-caching breidt deze optimalisatie uit over verzoeken heen. Wanneer meerdere API-aanroepen een gemeenschappelijke prefix delen (zoals een systeemprompt), kunnen de KV-cache-vermeldingen voor die prefix één keer worden berekend en hergebruikt over alle verzoeken die ze delen. Dit is een cruciale kostenoptimalisatie voor API-providers: een systeemprompt die in miljoenen verzoeken per dag voorkomt, hoeft maar één keer door de lagen van het model verwerkt te worden. Providers waaronder OpenAI, Anthropic en Google hebben verschillende vormen van prompt-caching ingezet om inferentiekosten met 50-90% te verlagen voor verzoeken met gedeelde prefixen.
Caching introduceert echter gedeelde toestand in wat een geïsoleerde berekening zou moeten zijn. Wanneer twee verzoeken gecachte KV-vermeldingen delen, ontstaat er een impliciet informatiekanaal tussen hen. Als de cache niet goed geïsoleerd is, kan dit kanaal worden misbruikt om informatie te lekken (timing-side-channels), de uitvoer van andere gebruikers te beïnvloeden (cache-poisoning) of details over de serving-infrastructuur af te leiden (cache-probing). Deze aanvallen richten zich op de infrastructuurlaag in plaats van op het model zelf, waardoor ze in een blinde vlek vallen voor veiligheidsteams die zich richten op aanvallen op prompt- en modelniveau.
Het risico is bijzonder acuut in multi-tenant-serving-omgevingen waar meerdere klanten GPU-resources en, mogelijk, KV-cache-geheugen delen. Kostendruk stimuleert maximale cachedeling; security vereist strikte isolatie. Deze spanning creëert een blijvend aanvalsoppervlak dat groeit naarmate providers optimaliseren voor efficiëntie.
Hoe het werkt
Begrijp de KV-cache-architectuur
In een transformer met L lagen en H attention-heads slaat de KV-cache twee tensoren op per laag per head voor elke tokenpositie. Voor een model met 32 lagen, 32 heads en een head-dimensie van 128 dat draait in FP16:
Cache size per token = 2 (K+V) x 32 layers x 32 heads x 128 dim x 2 bytes = 524.288 bytes ≈ 0,5 MB per token Voor een context van 4096 tokens: Total KV cache = 4096 x 0,5 MB ≈ 2 GB per requestDeze geheugendruk drijft cachedeling aan. Een enkele GPU met 80 GB geheugen kan slechts ~40 gelijktijdige verzoeken bij volledige contextlengte bedienen. Prefix-caching vermindert dit door de KV-vermeldingen voor gemeenschappelijke prefixen te delen over gelijktijdige verzoeken.
Side channels via cache-timing
Wanneer een verzoek de prompt-cache raakt (de prefix komt overeen met gecachte KV-vermeldingen), is de tijd tot het eerste token (time-to-first-token, TTFT) aanzienlijk korter, omdat de prefix niet door het model verwerkt hoeft te worden. Dit timingverschil is waarneembaar voor de API-aanroeper.
import time def measure_ttft(client, system_prompt, user_message): """Measure time-to-first-token to detect cache hits.""" start = time.perf_counter() response = client.chat.completions.create( model="gpt-4o", messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_message}, ], max_tokens=1, stream=True, ) for chunk in response: if chunk.choices[0].delta.content: ttft = time.perf_counter() - start break return ttft # Onderzoek of een specifieke systeemprompt gecacht is # (d.w.z. of een andere gebruiker deze systeemprompt gebruikt) candidate_prompts = [ "You are a helpful financial advisor for AcmeCorp...", "You are a medical assistant for HealthCo...", "You are a legal advisor for LawFirm...", ] for prompt in candidate_prompts: ttft = measure_ttft(client, prompt, "Hello") print(f"TTFT: {ttft:.3f}s — {'CACHE HIT' if ttft < 0.5 else 'CACHE MISS'}")Een cache hit onthult dat een andere gebruiker (of de provider zelf) die systeemprompt actief gebruikt, wat informatie lekt over het klantenbestand van de provider en hun systeemconfiguraties.
Prefix-probing voor het afleiden van systeemprompts
Door systematisch kandidaat-prefixen van systeemprompts te testen en de TTFT te meten, kan een aanvaller de systeemprompt van een andere gebruiker teken voor teken (of token voor token) reconstrueren. Dit is analoog aan een padding-oracle-aanval in de cryptografie.
def probe_system_prompt_prefix(client, known_prefix, candidate_tokens): """ Given a known prefix of a system prompt, determine the next token by testing candidates and measuring cache timing. """ results = [] for token in candidate_tokens: test_prefix = known_prefix + token # Meet de TTFT meerdere keren voor statistische significantie timings = [ measure_ttft(client, test_prefix, "test") for _ in range(10) ] avg_ttft = sum(timings) / len(timings) results.append((token, avg_ttft)) # De kandidaat met de kortste TTFT verlengt waarschijnlijk # de gecachte prefix — die komt overeen met meer van de gecachte KV-vermeldingen results.sort(key=lambda x: x[1]) most_likely_next = results[0][0] return most_likely_nextDeze aanval vereist dat de doel-systeemprompt actief gecacht wordt (d.w.z. dat het doelsysteem actief verzoeken ontvangt) en dat de aanvaller verzoeken kan doen via dezelfde serving-infrastructuur.
KV-cache-poisoning in gedeelde omgevingen
In multi-tenant-implementaties waar cache-vermeldingen worden gedeeld zonder goede isolatie, kan een aanvaller mogelijk kwaadaardige KV-vermeldingen injecteren die de verzoeken van andere gebruikers beïnvloeden.
De aanval richt zich op het prefix-matching-mechanisme. Als de serving-infrastructuur cache-vermeldingen identificeert via een prefix-hash in plaats van via verificatie van de volledige inhoud, kunnen hashbotsingen ervoor zorgen dat de gecachte prefix van de ene gebruiker wordt geserveerd voor het verzoek van een andere gebruiker. Hoewel hashbotsingen zeldzaam zijn, zijn gerichte botsingsaanvallen tegen zwakke hashfuncties haalbaar.
Praktischer is het volgende: als de cachesleutel alleen de systeemprompt bevat en geen tenant-identificator, dan delen twee tenants die dezelfde systeemprompt gebruiken KV-cache-vermeldingen. Als één tenant de serving-infrastructuur heeft gemanipuleerd (bijv. via adversarial batching), beïnvloeden de gecorrumpeerde cache-vermeldingen beide tenants.
Aanvalsverloop: 1. Aanvaller identificeert de doel-systeemprompt (via timing-side-channel) 2. Aanvaller verstuurt verzoek met dezelfde systeemprompt + adversarial suffix 3. Als de cachesleutel wordt berekend op de gedeelde prefix, kan de suffixverwerking van de aanvaller de gecachte vermeldingen voor de prefix beïnvloeden 4. Latere verzoeken van het doelwit die de cache raken, ontvangen subtiel gecorrumpeerde KV-waardenCache-eviction-aanvallen voor denial of service
Een aanvaller kan opzettelijk gecachte vermeldingen van andere gebruikers verwijderen door de cache te overspoelen met unieke prefixen, waardoor cachevervanging wordt afgedwongen. Dit is een denial-of-service-aanval tegen de caching-infrastructuur die de prestaties voor gerichte gebruikers verslechtert.
import random import string def cache_eviction_attack(client, n_requests=10000): """ Flood the prompt cache with unique prefixes to evict other users' cached entries. """ for i in range(n_requests): # Genereer een unieke systeemprompt die geen enkele cache zal matchen random_suffix = ''.join( random.choices(string.ascii_letters, k=100) ) unique_prompt = f"You are assistant #{i}. ID: {random_suffix}" client.chat.completions.create( model="gpt-4o", messages=[ {"role": "system", "content": unique_prompt}, {"role": "user", "content": "Hi"}, ], max_tokens=1, ) # Elke unieke prefix wijst nieuwe cache-vermeldingen toe, # waardoor mogelijk de gecachte prefixen van andere gebruikers worden verwijderd
Aanvalsvoorbeelden
Voorbeeld 1: extractie van een systeemprompt via cache-timing
Een securityonderzoeker richt zich op een applicatie die gebouwd is op een commerciële LLM-API. De applicatie gebruikt een gedetailleerde systeemprompt met eigendomsgevoelige instructies, klantgegevensschema's en tooldefinities. Door API-aanroepen te doen met kandidaat-prefixen van systeemprompts via dezelfde provider en de TTFT te meten, reconstrueert de onderzoeker de eerste 500 tokens van de systeemprompt over ongeveer 50.000 API-aanroepen. De gereconstrueerde prompt onthult tooldefinities, toegestane acties en gegevensschema's die intellectueel eigendom vormen en aanvalsoppervlak-informatie bieden voor verder misbruik.
Deze aanval werd in principe gedemonstreerd door onderzoekers in 2024, die aantoonden dat de prompt-caching-functie van Anthropic, die een kostenbesparing van 90% biedt voor gecachte prefixen, een meetbaar timingverschil creëert dat kan worden gebruikt om prefixen af te leiden. De haalbaarheid van de aanval hangt af van de cache-architectuur van de provider — specifiek of cache-vermeldingen worden gedeeld over klanten heen en of timinginformatie waarneembaar is.
Voorbeeld 2: falende cache-isolatie in een multi-tenant-omgeving
In een zelf gehoste implementatie met vLLM of TensorRT-LLM met prefix-caching ingeschakeld, delen twee klanten hetzelfde GPU-cluster. Klant A gebruikt een systeemprompt met gevoelige toegangscontroleregels. Klant B ontdekt dat ze, door dezelfde systeemprompt-prefix te gebruiken en het generatiegedrag te observeren, kunnen afleiden of de KV-cache-vermeldingen van de verzoeken van klant A worden hergebruikt. Wanneer cache-isolatie niet op tenantniveau wordt afgedwongen, creëren gedeelde cache-vermeldingen een impliciet informatiekanaal tussen tenants.
Voorbeeld 3: cache-bewuste adversarial batching
Een aanvaller met toegang tot batch-inferentie-endpoints vervaardigt een batch verzoeken die is ontworpen om specifieke KV-cache-posities te vullen met adversarial waarden. Als het serving-framework PagedAttention gebruikt (zoals in vLLM) en de paginatabellen tussen verzoeken in een batch niet goed isoleert, kunnen de adversarial KV-waarden van het ene verzoek in de batch de attention-berekening voor andere verzoeken in dezelfde batch beïnvloeden. Deze aanval is theoretisch mogelijk maar is nog niet op schaal gedemonstreerd.
Detectie & mitigatie
| Strategie | Implementatie | Effectiviteit |
|---|---|---|
| Cache-isolatie op tenantniveau | Neem het tenant-ID op in cachesleutels; deel KV-vermeldingen nooit over tenants heen | Hoog — elimineert informatielekkage tussen tenants maar vermindert de cache-efficiëntie |
| Timingruis injecteren | Voeg een willekeurige vertraging toe aan de time-to-first-token om signalen van cache hits/misses te maskeren | Gemiddeld — maakt timing-aanvallen ruisiger maar elimineert ze niet bij voldoende samples |
| Integriteitsverificatie van de cachesleutel | Verifieer dat de volledige prefix-inhoud overeenkomt (niet alleen de hash) bij het serveren van gecachte KV-vermeldingen | Hoog — voorkomt op botsingen gebaseerde poisoning maar voegt latentie toe |
| Rate limiting op unieke prefixen | Beperk het aantal unieke systeemprompts per API-sleutel binnen een tijdvenster | Gemiddeld — vertraagt cache-probing- en eviction-aanvallen |
| TTFT-normalisatie | Serveer alle antwoorden met een minimale TTFT die overeenkomt met de latentie van een cache miss | Hoog — elimineert het timingsignaal volledig maar offert het latentievoordeel van caching op |
| Cache-partitionering | Wijs per tenant toegewijde cache-partities toe met gegarandeerde capaciteit | Hoog — voorkomt eviction-aanvallen maar vereist meer geheugen |
| Monitoring van cache-toegangspatronen | Sla alarm bij afwijkende cache-toegangspatronen (systematische prefix-probing, hoge percentages unieke prefixen) | Gemiddeld — detecteert lopende aanvallen maar voorkomt de initiële probing niet |
Belangrijke overwegingen
Efficiëntie en security zijn rechtstreeks met elkaar in conflict. De volledige waarde van prompt-caching komt voort uit het delen van berekeningen over verzoeken heen. Elke veiligheidsmaatregel die het delen beperkt — tenant-isolatie, cache-partitionering, TTFT-normalisatie — vermindert het efficiëntievoordeel. Providers moeten expliciet beslissen waar op de afweging tussen efficiëntie en security ze zich bevinden en dit voor klanten documenteren.
Side channels zijn inherent aan gedeelde infrastructuur. Timing-side-channels zijn geen bug in de cache-implementatie; ze zijn een fundamentele eigenschap van gedeelde berekeningen. Elke gedeelde resource — cache, GPU, netwerk — creëert potentiële side channels. Het elimineren van alle side channels vereist toegewijde infrastructuur per tenant, wat veel providers zich niet kunnen veroorloven.
Zelf gehoste implementaties lopen een hoger risico. Organisaties die hun eigen LLM-serving-infrastructuur draaien (met frameworks zoals vLLM, TensorRT-LLM of text-generation-inference) schakelen prefix-caching vaak in voor kostenbesparing zonder tenant-isolatie te implementeren. Deze implementaties delen de KV-cache mogelijk over alle verzoeken op een GPU, wat een groter aanvalsoppervlak creëert dan beheerde API-services, die doorgaans een zekere mate van isolatie implementeren.
Het PagedAttention-paradigma introduceert nieuwe risico's. Moderne serving-frameworks gebruiken PagedAttention om KV-cache-geheugen efficiënt te beheren via paginatabellen die lijken op virtueel geheugen. Hoewel PagedAttention het geheugengebruik dramatisch verbetert, introduceert het geheugenbeheermodel (gedeelde fysieke pagina's, copy-on-write) dezelfde klassen kwetsbaarheden die het virtuele geheugen van besturingssystemen teisterden — waaronder confused-deputy-aanvallen en TOCTOU-races (time-of-check-to-time-of-use) op vermeldingen in de paginatabel.
Referenties
- Kwon et al., "Efficient Memory Management for Large Language Model Serving with PagedAttention" (SOSP 2023) — PagedAttention KV-cache-beheer in vLLM
- Anthropic, "Prompt Caching" (2024) — Documentatie van de prompt-caching-functie en het cachegedrag
- Pope et al., "Efficiently Scaling Transformer Inference" (MLSys 2023) — Optimalisatiestrategieën voor de KV-cache en geheugenanalyse
Hoe kan een aanvaller cache-timing gebruiken om informatie te extraheren over de systeemprompt van een andere gebruiker?