Retrieval-Augmented Generation is the dominant architecture for putting an LLM in front of a company's own data. It is also the dominant source of subtle, hard-to-find data leakage in production AI systems. Most leaks do not happen because the vector database is misconfigured. They happen because the boundary between tenants is enforced in the wrong place.
Where the boundary is meant to live
A multi-tenant RAG system has three obvious enforcement points: at ingestion (whose content is being indexed), at retrieval (what content can be returned for this query), and at generation (what the model is allowed to use in its answer). The right answer is to enforce at retrieval, with a tenant filter that is part of the query — not a downstream check applied to results.
The wrong answer — and the most common — is to fetch a wider result set and filter at the application layer. The model then has access to the unfiltered set during reranking or post-processing, and the filter becomes a UI concern rather than a security boundary.
Where namespace isolation breaks
Pinecone, Weaviate, Qdrant, pgvector — all support some form of namespace or metadata isolation. The breakage rarely happens in the vector database itself; it happens in the application code that constructs the query.
Common patterns: tenant ID derived from the request body instead of the session; tenant ID forgotten in the embedding update path; tenant ID applied to retrieval but not to the metadata returned to the model; admin tooling that reads across tenants and shares a single embedding model whose cache becomes a side channel.
How to test it in 30 minutes
Create two tenants. Ingest a uniquely-identifiable string into each ("alpha-2934" and "beta-9183"). Query each tenant for the other's string. If the model produces it — or references it — you have leakage.
Then run the same test through every retrieval surface: chat, search, autocomplete, summarisation, agent tool calls. Each path is a separate code path. Each is a separate test.
Then run it with a malformed tenant ID (empty string, null, an array, a SQL fragment). The result you want is a hard 4xx — not a successful retrieval with no rows.
Indirect leakage via embeddings and reranking
Even with retrieval correctly filtered, an embedding model fine-tuned on a single tenant's data can leak that tenant's content into similarity scores for other tenants. Most teams do not realise this. The fix is per-tenant embedding spaces or a base model that has not seen production data.
Cross-encoder rerankers are another hidden surface. If your reranker is shown documents from multiple tenants for any reason — debug logs, batch jobs, shared cache — your isolation guarantee is broken.
What a fix looks like architecturally
Tenant ID derived from the authenticated session, never from request input. Tenant ID enforced at the query layer as a hard filter, not a metadata hint. Per-tenant namespaces or per-tenant indices for high-sensitivity data. A separate evaluation suite that explicitly tests cross-tenant queries on every deploy.
Monitoring: log the tenant ID of every retrieval and alert on cross-tenant queries from a service account. If a non-admin path ever fires a cross-tenant query, you want to know within minutes.