Permission-aware retrieval means access control is applied before memory candidates reach the model. Do not retrieve everything and filter the final answer. Bind tenant, library, visibility, and user scope in the retrieval query first, then enrich, rank, cite, and answer only from allowed source artifacts.
Last updated: June 20, 2026.
Why is permission-aware retrieval different from app-layer filtering?
App-layer filtering can hide an answer after the model has already seen restricted text. That is too late. In a RAG or memory system, the sensitive moment is candidate retrieval. If an out-of-scope document enters the model context, the leak has already happened.
The NIST AI Risk Management Framework frames trustworthy AI around risk management and trustworthiness. The EU AI Act reinforces the importance of logging, governance, and risk controls for AI systems. For memory retrieval, the practical control is simple: enforce scope before the model sees data.
What does the Answer Engine tenant-isolation story show?
Issue #527 hardened the tenant-isolation story around content retrieval. The current repository code shows the pattern:
src/repositories/content.repository.tsstarts content lookup withWHERE c.tenant_id = $1.- Tag joins include
c.tenant_id = ct.tenant_idandct.tenant_id = t.tenant_id. - Shared-content joins include
cs.tenant_id = c.tenant_id. - Library scope uses
libraryRepository.effectiveMembershipSqlFragment(tenantId, libraryId, ...). src/services/qa/qa.service.tsstarts retrieval conditions withc.tenant_id = $1before full-text retrieval.- Vector retrieval prefilters allowed content ids when match filters apply, then enriches by tenant.
That is the product proof: scope is not a UI decoration. It is carried into repository SQL and retrieval prefilters before content is enriched for an answer.
Where should permissions be enforced?
Apply permissions at every candidate-producing layer:
| Layer | Required control |
|---|---|
| Content lookup | tenant_id, content id, status, visibility |
| Tag joins | Join on content id and tenant id |
| Library scope | Effective membership filter before ranking |
| Full-text search | Scope conditions before websearch_to_tsquery |
| Vector search | Prefilter allowed ids or pass scoped filters into the search function |
| Enrichment | Fetch full content by tenant and allowed ids only |
| Answering | Cite only retrieved allowed sources |
The MCP architecture docs describe tools and resources as server-exposed primitives. A memory MCP tool should never return resources outside the authenticated scope, even if the client asks broadly.
What can go wrong?
The classic failure is “filter after search.” A vector search returns nearest neighbors across a whole table, then the app removes disallowed records. This is risky because search scores were computed against data the requester should not reach, and implementation mistakes can leak candidates into logs or prompts.
Another failure is tenant-safe content lookup but tenant-unsafe joins. If content_tags, content_shares, or library membership joins do not include tenant ids, a row from another tenant can influence filtering or enrichment.
A third failure is permission-aware full-text search but permission-blind vector search. Both paths must enforce the same scope.
How do you test permission-aware retrieval?
Create tests that prove absence, not only presence:
- Tenant A asks for a fact only Tenant B has; no result should return.
- A non-owner asks for private content; no result should return.
- A user with a share asks for shared content; the result should return.
- A library-scoped question asks for a fact outside the library; no result should return.
- Hybrid search and full-text search should produce the same permission boundary.
The GDPR right to erasure is also relevant to lifecycle controls. A deleted or disabled source should not be retrievable by any delivery path.
What should you ask vendors?
Ask for the exact enforcement point. “We have RBAC” is not enough. Ask whether ACLs filter the vector candidate pool before retrieval, whether joins include tenant boundaries, whether logs contain out-of-scope snippets, and whether negative tests cover cross-tenant search.
Also ask for the layer where filters apply. A statement that the app supports roles is weaker than proof that candidate generation, enrichment, and citation assembly all use the same permission boundary.
Then use the Memory Leaderboard and RAG leaks docs to wrong users to compare the control surface.