AAI Agentic Handbook
Security & Tenancy

ACL (access control list)

Mid levelReviewed Oct 2026In 8 interview questionsIn 6 posts

Access control list: who may see a document. In RAG, ACLs must be enforced at retrieval time or the model will quote what the user can't open.

In plain English

An ACL (access control list) says which users or groups can access a resource. In a company search or assistant, documents come from systems like SharePoint, Google Drive or Confluence that already have permissions. If you index everything and forget those permissions, the AI happily summarises the CEO's salary review for an intern. Permission-aware retrieval stores who can see each chunk and filters every search by the asking user's identity.

Analogy

A library where some rooms need a staff badge. The librarian checks your badge before fetching a book from those rooms, not after reading it out loud to you.

Common pitfall

Filtering after retrieval. Taking top-10 from the whole index and dropping unauthorised hits returns zero or two results for most users, and if anyone skips the filter in one code path, the leak is complete.

How it actually works

Copy each source document's principals (users, groups) onto every chunk as metadata at ingest, resolve the user's group memberships at query time (from the IdP, cached for minutes), and filter inside the ANN search: a pre-filter or filtered HNSW (Qdrant, Weaviate, OpenSearch k-NN filters, pgvector with WHERE + RLS), never a post-filter after top-k. Permissions drift: ACL changes in the source must reach the index within minutes, so run a dedicated ACL sync and a Reconciliation job pass; for highly sensitive spaces, re-check access against the source API for the final top-k before generation. Group explosion is the scaling problem: users in 400 groups produce huge filter clauses, so flatten nested groups at ingest or use a permission token per document. Caches must key on ACL scope. OWASP's 2025 LLM Top 10 lists this under sensitive information disclosure and vector/embedding weaknesses. The LLM is never part of the access check: telling the model 'don't reveal confidential docs' is not access control.

What I'd ship on day one

Principals copied onto every chunk; nested groups flattened at ingest; user groups from the IdP (Okta, Entra ID) cached ≤5 min; filter in the ANN query (Qdrant/OpenSearch filters, pgvector + RLS); webhook-driven ACL sync plus 15-min ACL reconcile; source re-check for restricted spaces; ACL hash in cache keys; deny if group resolution fails.

Worked example

An internal wiki assistant indexes 2.4M Confluence pages. Each chunk carries allowed_groups (flattened, median 6 groups) and acl_hash. A query from a support engineer resolves to 38 groups via Okta (cached 5 min) and runs a filtered search in Qdrant. When an HR space is restricted, Confluence webhooks update chunk metadata within 2 minutes; the reconciliation job catches the 0.3% of changes whose webhooks were dropped. Finance spaces get a final per-document check against the Confluence API before generation.

In the interview

Permissions are enforced in the retrieval layer, not in the prompt: principals on every chunk, user groups resolved from the IdP, filter inside the vector search, fast ACL sync plus reconciliation, and a source re-check for the most sensitive spaces. Follow-up: 'what's your ACL staleness window?' Minutes for revocations, and I'd say exactly how it's measured.

01Source ACLsDrive, Confluence
02Ingestgroups on each chunk
03User → groupsIdP, 5 min cache
04Filtered ANNpre-filter, not post
05Source re-checksensitive spaces
06Generateonly allowed chunks
Access is decided before any text reaches the model.

Numbers worth knowing

Revocation propagation target
≤5 minuteswebhook sync; nightly-only sync means up to 24 h exposure
Group cache TTL
≤5 minuteslonger extends the revocation window
Source re-check cost
+50–200 msbatch permission check for the final top-k against the source API

How to decide

WhenDo this
Source has permissionsCopy principals to chunks; filter in search.
Space is highly sensitive (HR, legal, finance)Add a source re-check on final top-k.
Users belong to hundreds of groupsFlatten at ingest or use per-document permission tokens.
Group resolution or ACL lookup failsFail closed: search only public content or return an error.

Cost maths

ACL metadata is small: 6 groups × 16-byte ids per chunk across 11M chunks ≈ 1 GB. The source re-check costs one API call per query for sensitive spaces: at 50k such queries/day that's 50k calls, often within the source's free API quota. Against that: one leaked salary file or M&A doc.

Operating it

Time to scale up when…
  • Median filter clause >100 groups: move to flattened or token-based ACLs
  • Revocation lag p95 >15 min
  • New source systems with different permission models
What to monitor
  • ACL propagation lag (source change → index): alert p95 >5 min
  • Retrieved chunks failing source re-check: alert >0.1% (indicates stale ACLs)
  • Queries with failed group resolution: alert >0.5%

When it goes wrong

What users saw

Employees could get the assistant to summarise draft layoff plans from a restricted HR folder.

How it was caught

An employee reported it internally; audit logs showed 23 users had received chunks from the folder.

Root cause

The folder was restricted after ingestion; ACLs were only refreshed at full re-ingestion, monthly.

Fix

Webhook ACL sync with 2-minute propagation, 15-minute ACL reconcile, source re-check for HR spaces, and an access review of who saw what.

Sources

  1. Authorization Cheat Sheet — OWASP, 2025docs
  2. OWASP Top 10 for LLM Applications 2025 — OWASP, 2025spec

Check yourself

Three questions. Every option is explained once you answer.

1ConceptWhy must ACL filtering happen inside the ANN search rather than after top-k?
2ScenarioUsers belong to 400 nested groups, making filter clauses enormous. What do you do?
3CalculationACL metadata: 6 groups × 16-byte ids per chunk across 11M chunks. Roughly how much storage?