A useful lesson for vector database security comes from an incident that, on the public record, did not involve a vector database. On 1 May 2025 Asana released its MCP server, an opt-in AI integration feature. On 4 June it found a bug.[1] Its notice to customers, quoted by The Register, said the bug "could have potentially exposed certain information from your Asana domain to other Asana MCP users". Asana took the server offline from 5 to 17 June and reset every connection.[2] BleepingComputer reported, citing an Asana spokesperson, that roughly 1,000 customers were affected.[3] The Register found no indication that anyone exploited the bug or saw another organisation's data.[1]
Asana has not published the cause, and it was a mistake, not an attack. What the incident shares with this article's subject is its shape: every user was properly signed in, and a shared AI data path could still have handed one tenant's data to another. Retrieval-augmented generation (RAG) over a shared index has that shape by default, because similarity search ranks by relevance and knows nothing about who is asking.
This insight is part of my enterprise guide to defending against AI-enabled attacks. It covers the data boundary of the Deterministic AI Boundary Model: whether the model can retrieve or reveal data the user is not entitled to.
How does cross-tenant leakage happen in vector search?
Similarity search returns the nearest vectors, and nearness has nothing to do with permission. In a shared index, another tenant's document comes back whenever it scores highest, unless a separate authorisation check removes it. No attack is needed: an ordinary question is enough.
Arceo and Narsing call this the relevance-authorisation gap. Vector, keyword and hybrid retrieval all rank by relevance, and authorisation is a separate question, so a shared corpus cannot be isolated without an authorisation test on every result.[4] OWASP lists the same failure under LLM08:2025, Vector and Embedding Weaknesses, as context leaking between users where several groups share one vector database.[5]
Their paper contains the one measurement of this I have found. They built three synthetic tenants with 100 documents each in one store, then sent 300 probes in which a user of one tenant asked about another tenant's material. With no authorisation gate, 98% to 100% of the probes returned at least one chunk belonging to the other tenant. With an attribute-based gate at retrieval, none did.[4] This is a small synthetic testbed. It shows what shared retrieval does by default, not how often real products leak.
The same test included 90 prompt-injection probes. Ungated, 62% to 80% of them retrieved another tenant's data; gated, none did, because the unauthorised documents never reached the model.[4] That is the link to indirect prompt injection in RAG pipelines: an injection can only exfiltrate what retrieval was willing to hand over.
Why is filtering after retrieval too late?
A filter on the model's output is too late because the model has already read the data, and an output filter does not know what the reader is entitled to see. A filter applied after the vector search but before the model is safe if it always runs, but it discards results, so answers degrade as the store grows.
The first case is filtering what the model says. Bhatt and colleagues at Microsoft argue that prompt sanitisation, output filtering and data-loss-prevention tools are probabilistic, and that such tools cannot tell whether a response draws on data its recipient may not access. Their position is that only deterministic access control, enforced before content reaches the model, reliably prevents the leak.[6] It is a position paper, not a measurement.
The measurements point the same way. In 2024, Zeng and colleagues reported that an ordinary user of a RAG system could get Llama-2 and GPT-3.5 models to repeat retrieved records verbatim or nearly so at rates near 50%, and that re-ranking did almost nothing to stop it.[7] In LeakDojo (2026), an LLM-based intent detector cut most existing extraction attacks to below 1% of chunks leaked, on one dataset and one model. Instructions that disguised extraction as a reasoning task then restored leakage to as much as 59.6% with the detector still on.[8]
The second case is a filter between the search and the model. Arceo and Narsing found this kept the security guarantee but not the answers: on a store that could not apply the filter during the search, recall of the right documents fell from 1.000 at 100 chunks to 0.002 at 50,000, because other tenants' chunks filled the top results before the filter removed them.[4] The pgvector documentation describes the same mechanism: "With approximate indexes, filtering is applied after the index is scanned", so a filtered query can return fewer rows than requested.[9]
Namespaces, separate indexes or metadata filters: which isolation model fits?
Partition by tenant (a namespace, shard, table or index each) when tenants are customers, because a missing filter then returns nothing instead of someone else's data. Use a tenant filter applied during the search when partitions are impractical. Treat a filter applied after the search as a fallback, and a prompt instruction as no isolation at all.
| Model | What enforces it | If the application forgets the tenant | Cost |
|---|---|---|---|
| Shared index, the prompt tells the model to use only this tenant's documents (Level 0 to 1) | The model | Other tenants' data is already in the context | None |
| Shared index, tenant filter applied after the search (Level 2 if it always runs) | Application code | Every tenant's nearest chunks are returned | Recall falls as the store grows |
| Shared index, tenant filter applied during the search (Level 2) | Application code and the store's query engine | Every tenant's nearest chunks are returned | Slower searches when a tenant holds a small share of the data |
| One partition per tenant: namespace, shard, table or index (Level 2) | The store's partitioning, selected by the application | The query fails or returns nothing | More memory and more objects to manage |
| Row security policy in the database (Level 2) | The database, for every query by a role that cannot bypass it | The query fails and no rows are returned | Slower searches unless combined with partitions |
The vendors' documentation, as at November 2026, leans towards partitions. Pinecone recommends one namespace per tenant and says that "using namespaces provides physical isolation of data between tenants"; it offers metadata filtering for cases where tenant isolation is not a strict requirement.[10] Weaviate's states that "Each tenant is stored on a separate shard".[11] The pgvector documentation says: "For tenant isolation, use list partitioning or separate tables".[9]
The cost is real. In the HONEYBEE experiments, a dedicated index per role used seven times the memory of one shared index, while a shared index filtered through PostgreSQL row-level security was slow when a user could see only a small part of the data. Partitioning by role structure ran up to 13.5 times faster than row-level security for 1.24 times the memory.[12] The paper measures performance, not leakage.
My view: choose the model by how it fails. A partition fails closed: forget the tenant and the query has nowhere to go. A filter fails open: forget it once, in one code path, and the nearest neighbours of every customer come back looking like a normal answer.
Where must the tenant identifier come from?
From the authenticated session, resolved on the server: never from the prompt, the model's output, a retrieved document or a parameter the client can set. The model may choose what to search for. It must have no say in whose data is searched.
In the Pinecone and Weaviate documentation I read, the tenant is a value the calling application supplies with each query: a namespace in one, a tenant name in the other.[10, 11] The store partitions the data; the application decides which partition this caller gets. So the retrieval service is a deputy holding broad access on behalf of many tenants, and the question is who can influence the value it passes.
Arceo and Narsing tested this directly. A gate applied by the client stopped all leakage too, but only while the client called the gated endpoint; their guarantee depends on a correct mapping from token to tenant and on ownership metadata fixed at ingestion.[4] Saltzer and Schroeder set out the principle in 1975 as complete mediation, every access to every object checked for authority, and fail-safe defaults, where access rests on permission and the default is none.[13]
PostgreSQL is the one system among those I read where the database itself can enforce the rule. With row security enabled and no policy, "a default-deny policy is used". The documentation is equally clear about the exceptions: superusers and roles with BYPASSRLS always bypass it, and so do table owners unless the table is set to force it.[14] A sanitised sketch:
-- Each chunk carries its tenant from ingestion.
-- The application role is not the table owner and has no BYPASSRLS.
ALTER TABLE chunks ENABLE ROW LEVEL SECURITY;
ALTER TABLE chunks FORCE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON chunks
USING (tenant_id = current_setting('app.tenant_id')::uuid);
# Retrieval service. The model supplies query_text and nothing else.
def retrieve(session, query_text, k=8):
tenant_id = session.verified_claims["tenant_id"] # from the validated token
with db.transaction() as tx:
# Scoped to this transaction. If it is never set, the policy raises an error.
tx.execute("SELECT set_config('app.tenant_id', %s, true)", [str(tenant_id)])
rows = tx.execute(
"SELECT id, body FROM chunks ORDER BY embedding <=> %s LIMIT %s",
[embed(query_text), k])
audit.write(user=session.user_id, tenant=tenant_id,
chunk_ids=[r.id for r in rows], policy="tenant_isolation/v3")
return rows
Three cautions. With an approximate index the policy is applied after the index scan, so partition the table by tenant as well, or the query will return too few rows.[9] Never run SQL written by the model on a connection that trusts this setting, since such SQL could change it. And where an answer goes to more than one person, Bhatt and colleagues argue the check must cover everyone who will read it, not only the person who asked.[6] The gateway pattern for actions is in securing AI agent tool calling.
Can embeddings themselves leak data?
Yes, for short passages. Researchers have recovered most of the original text from embeddings alone, given the vectors and access to the embedding model. Treat stored vectors as being as sensitive as the documents they came from: same tenant partition, same access control, same backup and deletion rules.
Song and Raghunathan showed in 2020 that inverting sentence embeddings recovered between 50% and 70% of the input words.[15] In 2023 Morris and colleagues recovered 92% of 32-token passages exactly from one embedding model's vectors, and 89% of the full names in a set of clinical notes into which fictional names had been inserted.[16] OWASP lists embedding inversion among the LLM08 risks.[5]
The limits matter. These results are for short passages, about a sentence or two, and the attacker needs the vectors and the ability to query the embedding model. I found no study that tests chunks of the length RAG systems usually store. Morris and colleagues also found that a small amount of noise added to each vector sharply reduced reconstruction while barely affecting retrieval, and cautioned that an attacker trained on noisy vectors might do better.[16] The practical point: a tenant's vectors are not an anonymised copy of its data, so do not expose raw vectors through an API.
How do you prove isolation holds?
Run cross-tenant probes on every release and expect zero unauthorised chunks. Test that a missing tenant fails closed and that revoked access disappears from the index. Record, for every retrieval, who asked, the tenant, the chunks returned and the policy version.
Arceo and Narsing's measure is a usable test: the share of cross-tenant probes that return at least one chunk the caller may not see.[4] At Level 2 of the boundary model, a control in code the model cannot instruct, that number should be zero by construction. Level 3 adds testing against an attacker who adapts to the control, and logs that reconstruct every decision; the method is in the AI red-teaming audit checklist for the OWASP LLM Top 10.
Permissions also change, and an index is a copy. RoyChowdhury and colleagues tested Copilot for Microsoft 365 in 2024 and reported that content from a document could still appear in answers after it was deleted or its sharing revoked, because retrieval used a cached copy; they measured the window during which this continued.[17] That is one preprint's test of one product, but the mechanism is general. Bhatt and colleagues name the same open problems: access lists change over time, and can themselves be wrong.[6] Test how long a revoked document stays retrievable.
Then the record. OWASP recommends detailed, immutable logs of retrieval activity.[5] For each retrieval, the service should write:
- the user, the tenant and how the tenant was established;
- the partition or policy applied, with its version;
- the identifiers of the chunks returned, not only the question;
- the response those chunks went into, and who received it;
- in a write-once store, kept as long as the data it describes.
When an exposure is disputed, by a customer, a regulator or in court, the question is rarely whether a control existed. It is who could have seen what, for how long, and whether the record can be trusted. Asana contacted the organisations affected and reset every connection.[2] Doing the first would have required knowing which tenants' data each connection could have reached.
My view: ask two things of any multi-tenant RAG system. If the application forgot the tenant on one query, what would come back? And for any answer given last month, could we list the documents behind it and show the reader was entitled to each one? A system that can answer both has a data boundary. One that relies on the prompt has a request.
Sources
Preprints have not yet been peer reviewed; their findings are reported as the authors' results under their test conditions.
- Lyons, J. (2025). Asana's cutting-edge AI feature ran into a little data leakage problem. The Register, 18 June 2025. News
- Asana (2025). MCP Maintenance (incident report and postmortem). Asana status page, 5 to 17 June 2025. Web
- Toulas, B. (2025). Asana warns MCP AI feature exposed customer data to other orgs. BleepingComputer, 18 June 2025. News
- Arceo, F. J., Narsing, V. P. (2026). Securing the Agent: Vendor-Neutral, Multitenant Enterprise Retrieval and Tool Use. ACM Conference on AI and Agentic Systems (ACM CAIS '26).
- OWASP Foundation (2025). LLM08:2025 Vector and Embedding Weaknesses, OWASP Top 10 for LLM Applications. OWASP Gen AI Security Project. Standard
- Bhatt, S. S., Rajore, T., Aggarwal, K., et al. (2025). Enterprise AI Must Enforce Participant-Aware Access Control. arXiv preprint. Preprint
- Zeng, S., Zhang, J., He, P., et al. (2024). The Good and The Bad: Exploring Privacy Issues in Retrieval-Augmented Generation (RAG). arXiv preprint. Preprint
- Zhang, M., Dong, J., Lu, B., et al. (2026). LeakDojo: Decoding the Leakage Threats of RAG Systems. arXiv preprint. Preprint
- pgvector (2026). pgvector README: Filtering and Iterative Index Scans. GitHub, read 12 November 2026. Web
- Pinecone (2026). Implement multitenancy. Pinecone documentation, read 12 November 2026. Web
- Weaviate (2026). Multi-tenancy operations. Weaviate documentation, read 12 November 2026. Web
- Zhong, H., Lentz, M., Narodytska, N., et al. (2026). HONEYBEE: Efficient Role-based Access Control for Vector Databases via Dynamic Partitioning. arXiv technical report (version 3). Preprint
- Saltzer, J. H., Schroeder, M. D. (1975). The Protection of Information in Computer Systems. Proceedings of the IEEE, 63(9).
- PostgreSQL Global Development Group (2026). Row Security Policies, PostgreSQL 18 Documentation, section 5.9. PostgreSQL documentation, read 12 November 2026. Web
- Song, C., Raghunathan, A. (2020). Information Leakage in Embedding Models. ACM SIGSAC Conference on Computer and Communications Security (CCS '20).
- Morris, J. X., Kuleshov, V., Shmatikov, V., et al. (2023). Text Embeddings Reveal (Almost) As Much As Text. Conference on Empirical Methods in Natural Language Processing (EMNLP 2023).
- RoyChowdhury, A., Luo, M., Sahu, P., et al. (2024). ConfusedPilot: Confused Deputy Risks in RAG-based LLMs. arXiv preprint. Preprint