Practical LLM Security · RAG and Knowledge Security · Part 5 of 5

Propagate document deletion and permission changes through chunks, vector and keyword indexes, semantic caches, memory, and logs, then prove the change took effect.

Revocation is a distributed systems problem

Removing a document from the source system is the beginning of deletion in a RAG application, not the end. The document has been copied into chunks, embeddings, a keyword index, a reranker cache, a semantic answer cache, conversation transcripts, agent memory, evaluation datasets, and backups. Revoking a group's access is similar but subtler: nothing is deleted, yet every copy must stop being served to the former audience. The site's LLM data governance guide explains how to inventory those stores. This chapter focuses on propagation mechanics: how a change travels, how quickly, and how you prove it arrived.

A concrete failure: the cached answer after revocation

Northstar's finance team shares a pricing exception memo with the whole sales group by mistake. Within an hour the owner restricts it to finance. The source system updates immediately, and the nightly ACL sync updates chunk permissions eight hours later. In the meantime, a semantic cache returns a previously generated answer that quotes the memo to a salesperson who asks a similar question. The cache key was the normalized query text and the tenant, not the requesting principal or the ACL state, so the answer generated for an authorized user was reused for a newly unauthorized one. The citation still pointed to the memo, which the salesperson could no longer open, which is how the leak was eventually noticed.

The failure had three causes: a slow propagation path, a cache keyed without permissions, and no verification that revocation had reached derived stores.

Architecture: change events, epochs, and tombstones

Derived storeMechanismTarget propagation
Chunk ACL metadataChange event updates allowed groups and epochMinutes
Vector and keyword indexesTombstone filter immediately, rebuild laterImmediate for serving
Semantic and response cachesEpoch in cache key; purge by document idImmediate
Conversation memory and summariesLineage lookup; redact or retire derived itemsHours
Evaluation sets and analyticsLineage lookup; scheduled purgeDays
BackupsRetention expiry or crypto-shreddingPer retention policy

Subscribe to permission and deletion events from source systems instead of relying only on periodic sync. Every event increments an ACL epoch for the affected document and writes a tombstone or permission update to a small, fast store that the retrieval path consults on every request. Rebuilding an approximate index can take hours; serving must not wait for it. The tombstone filter removes deleted or newly restricted chunks from results immediately, and the index rebuild later removes the data physically.

Caches are where revocation most often fails. Include the ACL epoch, or a hash of the principal's group set together with the epochs of cited documents, in the cache key. When a document's epoch changes, entries that depended on it become unreachable. Also purge by document id using a reverse index from documents to cache entries. Periodic sync remains as a safety net to repair missed events.

Implementation: a revocation-aware cache

Illustrative python; adapt the persistence and identity adapters to your service.

import hashlib, json

def cache_key(tenant_id, group_snapshot, query_norm):
    material = json.dumps({"tenant": tenant_id,
                           "groups": sorted(group_snapshot.groups),
                           "group_epoch": group_snapshot.epoch,
                           "q": query_norm}, sort_keys=True)
    return hashlib.sha256(material.encode()).hexdigest()

def get_cached_answer(cache, key, principal, acl, tombstones):
    entry = cache.get(key)
    if entry is None:
        return None
    for doc_id, epoch in entry.cited_epochs.items():
        if doc_id in tombstones or acl.epoch(doc_id) != epoch:
            cache.delete(key)
            return None
        if not acl.can_read(principal, doc_id):
            cache.delete(key)
            return None
    return entry.answer

The cache entry records the epoch of every document it cites. Reads verify those epochs and the current permission before returning anything, so a revocation that arrives after caching still prevents reuse. This costs one metadata lookup per cited document, which is usually small compared with generation. Keep the cache scoped per tenant and per group snapshot; a semantic cache shared across users with different access is a deliberate cross-user data path and needs the same review as any other data-sharing feature.

Deletion requests and legal deadlines

Some deletions carry legal obligations. Article 17 of the GDPR gives a data subject the right to obtain erasure of personal data without undue delay where one of the listed grounds applies. Engineering can support those obligations by making every derived store discoverable through lineage and by producing a deletion receipt that lists each store, the action taken, and the time it completed. Whether a given request must be fulfilled, and how backups are handled, is a legal decision for your organization; the system should make any decision executable and verifiable. The ADK Java guide to the right to be forgotten across sessions and memory shows a framework-specific purge path that complements this design.

Tradeoffs and worked case

Event-driven revocation needs reliable delivery from source systems and idempotent handlers, because events may arrive twice or out of order. Use the epoch to ignore stale events. Including group snapshots in cache keys lowers hit rates for organizations with many unique group combinations; measure and accept the cost, or cache retrieval results per document set rather than final answers. Immediate tombstones add a lookup on the hot path, so keep the tombstone store small and in memory, and compact it after index rebuilds.

Replay the pricing memo case with the new design. The owner's restriction emits an event; the memo's epoch increases from 7 to 8 and its chunk permissions are updated within two minutes. The cached answer records the memo at epoch 7, so the salesperson's request misses the cache and retrieval excludes the memo. A finance user still receives a correct answer, which is regenerated and cached under the new epoch. A reverse-index purge removes the old entry, and the lineage service marks two memory summaries for review.

Ordering, idempotency, and the stores you forget

Change events arrive out of order. A document can be shared, restricted, and shared again within minutes, and the three events may reach the retrieval service in any sequence. Attach the source system's version or modification sequence to each event and apply an event only if it is newer than the state already recorded. Handlers must be idempotent, because at-least-once delivery means duplicates are normal. A deletion event should write a tombstone first and perform physical deletion afterwards; if the physical step fails, the tombstone still keeps the content out of results while a retry runs.

Several stores are routinely missed. Query logs and traces often contain retrieved text verbatim. Evaluation datasets copy real questions and answers to measure quality. Fine-tuning or distillation sets may include assistant outputs that quote documents. Analytics exports may contain embeddings, which the poisoning chapter explains can reveal source text. Each of these needs an owner, a lineage link back to document identifiers, and a defined action for revocation and deletion, even if that action is a scheduled purge rather than an immediate one.

Backups need a policy rather than a promise. Restoring a backup can resurrect deleted documents and old permissions together. Keep the tombstone and epoch store outside the backup set, or replay it after every restore, so that a restored index is filtered by current decisions before it serves traffic.

Verification: prove propagation with canaries

Assertions in unit tests are necessary but not sufficient, because propagation crosses services. Maintain synthetic canary documents in every source system. On a schedule, revoke a canary from a test group, then query as a test principal through the real retrieval and cache paths and record the time until the canary disappears from results, cached answers, and citations. Do the same for deletion. Alert when propagation exceeds its target. The receipt for a real deletion should cite the same measurements: which stores were checked, by which query, and when. The companion secure retrieval lab lets you revoke a synthetic document and compare a permission-aware cache with a cache keyed only by query text.

Practice and continue

Open the Secure retrieval: permissions, caches, and citations lab to change the assumptions with deterministic synthetic data and inspect each decision. This chapter belongs to the RAG and Knowledge Security group of Practical LLM Security, which builds on the 25-chapter abuse and fraud prevention series.

Sources and implementation scope

Primary references checked October 16, 2026. Framework details follow the linked documentation and, for ADK, the google-adk 2.12.0 package source; pin and test the version your application uses. The Northstar scenarios, policies, figures, and code are original illustrative designs, not measured production results or complete integrations.

Decide authority with verified identity and provenance, enforce it where the effect happens, and test both containment and legitimate use.