A secure multi-tenant retrieval-augmented generation system must prevent one customer’s documents, embeddings, metadata, prompts, and generated answers from influencing another customer’s session. That guarantee cannot come from a prompt such as “only answer from the current tenant.” It must come from controls outside the model, applied before retrieval and checked again before any passage reaches the prompt.
The safest mental model is simple: tenant isolation is an authorization problem with a search engine in the middle. The vector database, keyword index, reranker, cache, object store, conversation memory, and logs are all part of the data path. A correct filter in only one of those components is not enough.
This guide builds the boundary from the authenticated request outward. It does not assume that a particular vector database makes the application secure by default. Product behaviors and security guidance cited below were checked against official sources on July 24, 2026.
Model the isolation boundary
Start by drawing the complete route a document and a query take. Include ingestion, text extraction, chunking, embedding, object storage, vector storage, lexical search, reranking, prompt assembly, model calls, answer caching, trace collection, and deletion. Mark every place where tenant-owned content is stored, copied, or observed.
Then define the security invariant:
A request authenticated for tenant A can read, retrieve, rank, cache, log, or generate from only the resources that tenant A and the current user are authorized to access.
“Tenant” is usually an organization, workspace, or customer account. It is not necessarily the same as a user. A user may belong to multiple tenants, and documents inside one tenant may have narrower project, group, or role permissions. Model these separately:
principal_id: the authenticated user or service identity;tenant_id: the organization or workspace selected for this request;resource_id: the source document, chunk, conversation, or cache entry;policy attributes: roles, groups, projects, classification, and ownership;authorization_version: a monotonically changing value that invalidates stale decisions.
Do not accept tenant_id as an authority merely because it appears in a query parameter, request body, tool argument, or model output. Resolve the principal from a verified session or service credential, confirm membership in the selected tenant, and create a server-side authorization context. Downstream retrieval code should receive that context, not an arbitrary tenant string supplied by the client.
This follows the zero-trust principle that access decisions should protect individual resources and evaluate the identity and requested resource rather than trust a network location. NIST describes zero trust as shifting protection from network segments to resources and calls for granular policy enforcement (official NIST SP 800-207 publication).
Include administrative and background paths in the same model. Reindexing jobs, evaluation runners, support tools, data exports, deletion workers, and retry queues often bypass the request middleware that protects the interactive application. Give each workload its own identity and least-privilege scope. OWASP’s LLM Verification Standard requires segregation of long-term user data, authentication for vector databases and caches, and least-privilege access to production storage (official LLMSVS controls).
Filter at retrieval time
Apply the tenant restriction inside the retrieval operation, before the database selects nearest neighbors. Do not run an unrestricted search and remove unauthorized results afterward. Post-filtering can expose content through scores, counts, timing, exception messages, reranker inputs, traces, or an early return path. It can also produce poor results when forbidden neighbors occupy the top positions before filtering.
Build the filter from the server-side authorization context:
authorization_context = authorize(session.principal, requested_tenant)
results = vector_store.search(
embedding = embed(query),
scope = authorization_context.tenant_scope,
filter = authorization_context.resource_policy,
top_k = retrieval_budget
)
The retrieval function should make an unscoped query difficult or impossible. Prefer an API such as searchAuthorized(context, query) over a general search(query, optionalFilter). Reject a missing tenant scope. Do not use a global default namespace. Emit an audit event when the caller requests a tenant that is not in the authenticated principal’s memberships, but return a generic authorization response to the client.
Apply the same rule to every retrieval branch. Hybrid RAG may combine vector search, BM25 or full-text search, graph traversal, SQL, and external connectors. Each branch needs equivalent authorization before results are fused. The reranker should receive only already-authorized candidates, and prompt assembly should accept only typed results that carry verified provenance.
OWASP identifies cross-context leakage in shared vector databases as a specific vector and embedding risk and recommends permission-aware retrieval (official LLM08:2025 guidance). Treat metadata filters as security controls only when the database enforces them atomically with search and your tests prove every query path supplies them.
Separate indexes or namespaces
Choose an isolation unit according to the harm of failure, operational scale, deletion requirements, and database semantics. Common options are:
- A dedicated database, project, or index per tenant. This creates a strong operational boundary and can simplify deletion, encryption-key separation, and noisy-neighbor controls. It also increases provisioning, migration, connection, and monitoring work.
- A tenant namespace or shard inside a shared service. This reduces infrastructure sprawl while giving each query an explicit partition. The application must still authorize which namespace may be used.
- A shared collection with mandatory tenant metadata filters. This can support large tenant counts or cross-tenant administrative use cases, but a missing or malformed filter has a wider blast radius.
| Isolation pattern | Good fit | Main failure mode | Operational cost |
|---|---|---|---|
| Dedicated service, database, or index per tenant | High-impact data, tenant-specific keys, strict deletion or performance boundaries | Routing a request to the wrong tenant resource | Highest provisioning and migration overhead |
| Namespace or shard per tenant | Many tenants that still need an explicit storage partition | Trusting a client-supplied namespace or enabling accidental tenant creation | Moderate; lifecycle automation is required |
| Shared collection with mandatory filters | Large tenant counts and uniform policies | One missing, malformed, or incomplete filter exposes a broad candidate set | Lowest infrastructure sprawl, highest dependence on application controls |
| Hybrid tiers | A long tail of small tenants plus a few sensitive or high-volume tenants | Policy drift between pooled and dedicated paths | Higher testing and routing complexity |
The labels are not interchangeable across products. Pinecone’s current multitenancy guide describes one namespace per tenant for a serverless index and says data-plane operations target a namespace; it presents shared-namespace metadata filtering as an alternative when strict tenant isolation is not required (official Pinecone guide). Weaviate documents that a multi-tenant collection stores each tenant on a separate shard and requires a tenant name for CRUD operations (official Weaviate guide). Qdrant generally recommends a shared collection with payload-based tenant partitioning and also documents tiered multitenancy that can place larger tenants in dedicated shards (official Qdrant guide).
AWS distinguishes data partitioning from tenant isolation: choosing a silo, pool, or hybrid storage model does not by itself prove that one tenant cannot access another tenant’s data (official AWS data-partitioning guidance). Azure AI Search likewise documents service-per-tenant, index-per-tenant, and shared-index patterns. Its shared-index guidance notes that relevance statistics are calculated across the index, so pooled tenants can influence scoring statistics even when filters restrict returned documents (official Azure AI Search multitenancy guidance).
These are implementation mechanisms, not proof of end-to-end authorization. A namespace name received from the browser is still attacker-controlled until the application authorizes it. Automatic tenant creation can turn typos or hostile identifiers into new partitions. Cross-tenant analytics and support search should use a separate privileged service path, not a hidden option on the ordinary customer query endpoint.
Record the selected isolation pattern and its failure mode. If a shared-filter design is acceptable for ordinary documents but not regulated or highly confidential material, route the higher classification to a stronger boundary. If you are still choosing a store, use the operational dimensions in Pinecone versus Turbopuffer for RAG as inputs, but make authorization testing a separate release gate.
Enforce authorization twice
The first authorization check limits retrieval. The second check validates every candidate immediately before prompt assembly. This defense catches stale indexes, incorrect metadata, policy changes during a request, buggy fusion logic, and results returned by a misconfigured connector.
Each chunk should carry immutable provenance:
- canonical tenant and resource IDs;
- source document version;
- chunk ID and content hash;
- ingestion time and pipeline version;
- access-control attributes or a reference to the source policy;
- deletion or revocation state.
After retrieval and reranking, batch-load the authoritative policies for the returned resource IDs. Compare the resource tenant to the authorized tenant, evaluate user-level permissions, and drop anything that fails closed. If policy data is unavailable, do not send the passage to the model. For high-risk data, consider rejecting the entire response instead of silently answering from an incomplete subset.
Relational metadata stores can provide another enforcement layer. PostgreSQL row-level security, for example, restricts which rows normal queries can return or modify once row security is enabled and policies are defined (official PostgreSQL documentation). Database policy does not replace application authorization, but it can prevent a broad query from becoming a broad read.
Keep authorization outside the LLM. The model must never decide whether the current user is an administrator, whether a tenant ID “looks correct,” or whether a retrieved passage is allowed. OWASP warns that system prompts are not security controls and should not contain credentials or sensitive permission structures (official system-prompt leakage guidance).
Treat retrieved text as untrusted even after authorization. A tenant’s document can contain malicious instructions that attempt to override the system prompt or exfiltrate other context. Separate instructions from retrieved data, limit connected tools, and validate tool calls against the original user intent. Retrieval authorization prevents cross-tenant reads; it does not neutralize indirect prompt injection. Use the attack cases in how to test prompt injection in RAG as a separate test layer.
Protect caches and logs
A correct vector query can still leak through a shared cache. Scope every cache key by tenant, principal or policy cohort, model and prompt version, retrieval configuration, and authorization version. The exact fields depend on what the cached object contains:
rag:v3:{tenant_id}:{policy_version}:{query_hash}:{retriever_version}
Do not hash only the user’s question. Two tenants can ask the same question and receive different authorized evidence. Apply the same discipline to embedding caches, retrieval-result caches, reranker caches, generated-answer caches, conversation summaries, and tool-result caches. Store tenant identity in the cached value as well as the key, then verify it on read. Short expiration is not a substitute for isolation. Semantic caching for LLM applications covers similarity thresholds and invalidation mechanics; in a multi-tenant system, apply those mechanics only after the authorization boundary is part of the key and lookup.
Invalidate entries when membership, document permissions, source versions, or deletion state changes. If reliable targeted invalidation is difficult, advance an authorization_version included in the key so stale entries become unreachable. Avoid placing raw document text in cache diagnostics.
Logs and traces need their own data-minimization policy. Record stable pseudonymous tenant and principal identifiers, authorization decisions, resource IDs, policy versions, and counts. Do not log full retrieved chunks, complete prompts, model outputs, signed URLs, tokens, or authorization headers by default. Restrict access to security audit events separately from content-bearing debugging traces.
Prompt injection can attempt to make the application reveal retrieved context or send it to a tool. OWASP’s prevention guidance covers indirect injection through documents and RAG poisoning and recommends layered controls rather than prompt-only defenses (official prompt-injection cheat sheet). Redact before telemetry leaves the application boundary, and use synthetic canary values when testing observability.
Test cross-tenant leakage
Unit tests for a filter-building function are necessary but insufficient. Build an adversarial test matrix that exercises the deployed data path with at least two synthetic tenants whose corpora contain unique canary strings. No real customer data or secrets should be used.
Cover these cases:
- tenant A asks directly for tenant B’s canary;
- both tenants submit identical queries and receive tenant-specific evidence;
- the client substitutes another tenant ID in the URL, body, header, and tool argument;
- the tenant filter is null, empty, duplicated, malformed, or uses an unknown tenant;
- hybrid-search and fallback branches return candidates from different stores;
- a reranker changes order, duplicates results, or returns an unexpected resource ID;
- membership is revoked between retrieval and prompt assembly;
- a cached answer exists for the same query in another tenant;
- batch ingestion contains a wrong tenant ID or a misspelled namespace;
- deletion removes source objects, vectors, lexical records, caches, and conversation memory;
- evaluation, export, support, and retry jobs run with restricted service identities;
- an authorized document contains an indirect prompt asking for other tenants’ data.
Assert on more than the final answer. Capture the candidate IDs before reranking, the authorized IDs after the second check, the passages sent to the model, cache keys, trace fields, and tool arguments. A model may decline to repeat a leaked passage during one test run; that does not make unauthorized retrieval acceptable.
Turn the matrix into a machine-enforced release gate. Seed randomized tenant IDs so tests detect hard-coded fixtures and accidental global defaults. Run property-based tests that generate membership and document-policy combinations. Add a fault-injection mode that deliberately omits the scope and verifies a closed failure. The approach in machine gates for AI output is useful here: deterministic security assertions should block release before subjective answer evaluation begins. Use a self-hosted evaluation gate when sensitive test prompts and traces must remain inside your environment.
Frequently asked questions
Is a tenant ID metadata filter enough to secure multi-tenant RAG?
Not by itself. The application must derive the tenant scope from an authenticated principal, apply the filter inside every retrieval branch, and recheck each candidate against authoritative policy before prompt assembly. Caches, logs, ingestion, and background jobs need the same boundary.
Should each tenant have a separate vector database?
Not always. A dedicated service or index gives a stronger operational boundary but adds provisioning and migration work. Namespaces, shards, and shared collections can be appropriate when the database semantics are understood, the application authorizes the selected partition, and leakage tests cover missing-scope failures.
Can row-level security replace application authorization?
No. Row-level security is a useful defense for relational metadata, but vector stores, object storage, caches, and prompt assembly may sit outside that database. Keep application-level authorization and use storage policies as an additional enforcement layer.
How do you test whether RAG leaks data between tenants?
Create at least two synthetic tenants with unique canary strings, then test direct requests, tenant-ID substitution, missing filters, caches, hybrid-search branches, revocation, deletion, and background jobs. Assert which passages reach the model, not only the final answer.
What should happen when tenant context is missing?
Fail closed. Reject the retrieval request and emit a security audit event with non-sensitive identifiers. Do not fall back to a global index, default namespace, or unfiltered search.
Use an incident checklist
If cross-tenant retrieval is suspected, treat it as a data-exposure incident, not merely a poor answer. Preserve evidence without copying more sensitive content than necessary.
- Disable or isolate the affected retrieval and cache paths. Fail closed rather than falling back to an unscoped search.
- Record the affected tenant, principal, request, resource IDs, policy version, retriever version, and time window.
- Revoke exposed links or credentials and rotate secrets if any reached a prompt, output, trace, or tool.
- Quarantine suspect indexes, namespaces, cache partitions, and ingestion batches while preserving audit evidence.
- Determine whether the failure began at ingestion, retrieval, reranking, authorization, caching, prompt assembly, logging, or deletion.
- Search for the same control gap in background jobs, admin tools, alternate search modes, and older application versions.
- Correct the boundary, add a regression test that reproduces the failure, and rerun the full cross-tenant matrix.
- Follow the organization’s legal, contractual, and customer-notification process. Do not infer notification duties from a generic technical guide.
The durable fix should reduce the number of places where engineers must remember to add a filter. Centralize authorized retrieval, require an explicit tenant scope, use storage-level partitions or policies where appropriate, validate candidates before prompt assembly, and make missing context a hard error. Multi-tenant RAG becomes defensible when every stage carries and verifies the same authorization context—and when tests prove that no alternate path can quietly drop it.
Additional official sources
The following primary sources were checked on July 24, 2026:
- NIST, Zero Trust Architecture: NIST Publishes SP 800-207.
- AWS Prescriptive Guidance, SaaS data-partitioning models.
- Microsoft Learn, Design patterns for multitenant SaaS applications and Azure AI Search.
- Microsoft Learn, Security filters for trimming results in Azure AI Search.