Document-Level Permissions in RAG
Propagating source-document ACLs into the vector index so retrieval never returns what a user cannot see.
Document-level permissions in RAG are the source system’s per-document access controls — who may read which file — copied onto every chunk in the vector index and enforced at retrieval time so similarity search never returns what the asking user cannot see. Embedding strips ACLs unless you deliberately carry them; without that step, RAG becomes a privilege-escalation path through your own corpus.
Why does embedding strip document permissions?
Chunking and embedding reduce a document to vectors and text — the source system’s owners, sharing lists, and inheritance flags do not travel unless you attach them as metadata on every chunk (Wavect, 2026; App Lab, Dec 2025). A vector store ranks by similarity, not identity; the same query from two users returns the same neighbours unless a permission filter is injected — the failure mode covered on access control in RAG retrieval.
The practical failure is direct: the model can compose a fluent answer from a document the user was never allowed to open. Kapil Uthra’s ACL-aware RAG write-up (2026) puts the enterprise blocker cleanly — naive RAG will summarise a restricted board deck for anyone who phrases the right query, because the index has no concept of who is asking.
How do you propagate source ACLs into the vector index?
Resolve the effective ACL at ingest and materialize it as filterable metadata on every chunk before embed — not on the document record alone (Microsoft ISE SharePoint blog, 2026; Azure AI Search document-level access overview, 2026-05-01-preview).
The SharePoint pattern Microsoft ISE documents is representative: fetch permissions via Microsoft Graph
(GET /sites/{site-id}/drive/items/{item-id}/permissions), normalize identities to Microsoft Entra ID object
IDs rather than emails, resolve inheritance once at ingest, then store allowedUsers and
allowedGroups on each chunk. Use Sites.Selected for least-privilege ingestion rather than tenant-wide
read scopes. Azure AI Search lists four document-level approaches as of the 2026-05-01-preview API: security filters,
native ACL/RBAC scopes, Microsoft Purview sensitivity labels, and SharePoint ACL ingestion — pick by source system and
identity model.
Every chunk should carry at minimum: document_id, tenant_id, allowed principals (users and/or groups),
permissions_version or acl_version, and ingest timestamp — so stale metadata is detectable and revocable
without re-embedding unchanged text (Truto, 2026; App Lab, Dec 2025).
Why does chunking affect document permissions?
A chunk that crosses a permission boundary inherits the wrong ACL — if one chunk merges a public section and a restricted section but is tagged with the public ACL, anyone who can read the public section retrieves the restricted text (App Lab, Dec 2025).
The fix is permission-aware chunking: split at permission boundaries and tag each chunk with the most restrictive ACL of any text it contains. A document whose executive summary is open to all employees but whose salary-band appendix is HR-only needs independent chunk ACLs per section — not one document-level tag applied after a naive text split.
How do you enforce document permissions at query time?
Pre-filter the vector query with the asking user’s identity and group memberships so unauthorized chunks never enter the candidate set (App Lab, Dec 2025; Kapil Uthra, 2026). Three rules recur across the live teardown:
- Retrieve with the end-user’s identity, not a shared service account — on-behalf-of OAuth propagates per-user trimming; a service-account-only chain cannot enforce document-level RBAC (Wavect, 2026).
- Store group IDs on chunks, resolve membership at query time — lower cardinality and no re-index when group membership changes (Wavect, 2026).
- Pre-filter at the ANN query — metadata filters on Weaviate (multi-tenancy + filters), Pinecone namespaces/filters, or pgvector row-level security are the named patterns in App Lab’s Dec 2025 guide; Weaviate leads ordered store mentions.
Telling the model not to reveal a restricted document is not a control — the OWASP RAG Security Cheat Sheet treats prompt restrictions as bypassable. Deeper pre-filter vs post-filter trade-offs live on access control in RAG retrieval.
How do you keep document permissions in sync?
Treat permission changes as first-class sync events, not only content updates — materialized ACLs go stale until the index is refreshed (Microsoft ISE, 2026: a revoked SharePoint grant may persist in the search index until the next ingestion run).
Three strategies, ordered by urgency:
- Event-driven revocations — webhooks or change feeds for permission removals; App Lab (Dec 2025) recommends event-driven sync for security-critical removals first.
- Polling or scheduled re-sync — acceptable for permission additions; periodic full re-sync as safety net.
- Query-time source check — optional last-mile verification for high-sensitivity corpora when metadata lag is unacceptable (Wavect, 2026 freshness fork).
Two leak windows matter (Wavect, 2026): sync lag after a source-side revocation, and the inherited-scope blind spot — parent permission changes that are not propagated to children with inherited ACLs. Azure AI Search’s 2026-05-01-preview SharePoint ACL docs note that inherited-scope changes require an explicit permissions resync, not only incremental content indexing. Deletions must cascade to chunks and embeddings — orphaned vectors after delete are the stale-index failure; erasure depth is on RAG and GDPR.
How do you normalize permissions across SaaS sources?
Each source models authorization differently — ingest with an identity that can read content and ACLs, then map every source to one normalized shape before chunk metadata is written (Truto, 2026; Wavect, 2026).
A lean taxonomy from the union: Google Drive ReBAC roles on files and folders · SharePoint/OneDrive cascade
site→library→item with broken inheritance · Confluence space permission intersected with page restrictions (Wavect:
the Cloud restrictions API does not return inherited restrictions — walk ancestors or leak restricted child pages) ·
Notion workspace and teamspace rules. On Microsoft Graph, use grantedToV2, not deprecated grant fields (Wavect,
2026). Full connector mechanics belong on connectors; flattening graph-like ACLs
into simple tags can explode metadata — external policy/ReBAC engines are the escape hatch on
access control.
How do you test document-level permissions in RAG?
Adversarial role tests on the live retrieval path — not relevance evals alone (Kapil Uthra, 2026). Minimum suite:
- Same natural-language query as two roles must not return restricted chunks to the lower role.
- Cross-tenant queries return empty or isolated namespaces only.
- A revoked user fails on the next request after sync.
- Requests missing identity context fail closed — they do not fall back to search-everything.
- Chunk ACL metadata matches source permissions after a sync cycle.
Wire the suite into CI where you can; keep the trail in audit logging.
What are document-level permissions in RAG?
They are the source system's per-document access controls — who may read which file — materialized as filterable metadata on every chunk in the vector index and enforced at retrieval time. Similarity search must never return a chunk the asking user is not authorized to read in the source system.
Does RAG respect SharePoint permissions by default?
No. Embedding strips ACLs unless you ingest permissions alongside content and security-trim at query time. Native products like Microsoft 365 Copilot build this in; custom RAG pipelines must materialize SharePoint ACLs on chunks and filter with the signed-in user's Entra ID identity and group memberships.
Should I store user IDs or group IDs on each chunk?
Group IDs. They are lower cardinality, and a membership change needs no re-index — only query-time group resolution. Store stable object IDs (Entra GUIDs on Microsoft stacks), not display names or emails that can change.
Is post-retrieval filtering enough for document permissions?
No. Post-filtering retrieves forbidden chunks first, wastes top-k slots, and may leave the model having already processed restricted text. Enforce authorization in the vector query so unauthorized chunks never enter the candidate set — see access control in RAG retrieval for the full pre-filter vs post-filter analysis.
Why does chunking matter for document permissions?
A chunk that merges a public section and a restricted section but inherits the public ACL leaks the restricted text to anyone who can retrieve the chunk. Chunk at permission boundaries and tag each chunk with the most restrictive ACL of any text it contains.