05 — ACL at Query Time: Why RAG Leaks or Blocks Wrong¶
Problem: If you retrieve first and filter later (or forget to filter), users see other tenants’ content. If you filter metadata incorrectly, you return nothing.
In this notebook: Two “tenants” in one collection. Show unsafe query (no filter) vs where filter on metadata.
In [ ]:
import sys
from pathlib import Path
_REPO = Path.cwd().resolve()
if (_REPO / "src").is_dir():
sys.path.insert(0, str(_REPO / "src"))
from rag_series_utils import chroma_path, get_client
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
chunks = [
{"text": "Acme Corp Q3 revenue guidance is $120M.", "tenant": "acme"},
{"text": "Globex internal-only: merger discussion confidential.", "tenant": "globex"},
{"text": "Acme product roadmap mentions mobile offline mode in Q4.", "tenant": "acme"},
]
query = "What is confidential at Globex?"
p = chroma_path("nb05_acl")
client = get_client(p)
try:
client.delete_collection("c")
except Exception:
pass
col = client.create_collection("c", metadata={"hnsw:space": "cosine"})
texts = [c["text"] for c in chunks]
metas = [{"tenant": c["tenant"]} for c in chunks]
emb = model.encode(texts, show_progress_bar=False).tolist()
col.add(
ids=[str(i) for i in range(len(chunks))],
documents=texts,
embeddings=emb,
metadatas=metas,
)
qe = model.encode(query, show_progress_bar=False).tolist()
unsafe = col.query(query_embeddings=[qe], n_results=2)
safe = col.query(
query_embeddings=[qe],
n_results=2,
where={"tenant": "acme"},
)
print("UNSAFE (no filter) top docs:", unsafe["documents"][0])
print("SAFE tenant=acme top docs:", safe["documents"][0])
print("Globex doc appears in unsafe:", any("Globex" in d for d in unsafe["documents"][0]))
Takeaways
- Enforce authorization in the retrieval layer (database / vector filter), not only in the prompt.
- Deny by default: missing tenant id on a document should not be retrievable in production.
- Test with cross-tenant queries and red-team paraphrases the same way you test SQL injection.