Permission-aware retrieval: the security question enterprise AI keeps getting wrong
The Curiosity Team
Permission-aware retrieval: the security question enterprise AI keeps getting wrong
Every enterprise AI project reaches the same uncomfortable moment. The assistant works. It answers questions from company data, cites its sources, and people start to trust it. Then someone asks: what stops it from telling me something I'm not allowed to see?
That question rarely has a good answer, because permissions were an afterthought. The data was indexed, the model was wired up, and access control got bolted on at the end, usually as a filter on the way out. That's the part most teams get wrong, and it's worth understanding why.
Where the leak actually happens
The common design looks reasonable. The assistant retrieves whatever is relevant, the model writes an answer, and a check at the end hides any source the user wasn't cleared for. Sources they can't access don't appear in the citations.
The problem is that by the time you filter the citations, the model has already read the restricted document. It reasoned over the salary figure, the unreleased financials, the HR note, and folded them into the summary. You can hide the link to the source. You can't easily un-say the sentence the model wrote because of it.
An employee asks the assistant to summarise "everything we know about the Q3 reorg." Retrieval pulls in a restricted planning doc. The citation gets stripped on the way out, so it looks clean. But the summary still mentions the two roles being cut, because the model saw them. Nobody attached a file. The information still leaked.
Permissions belong to the data, not the response
The fix is to move the check upstream. The model should never retrieve a record the user can't access in the first place, so there's nothing to leak, redact, or reason over by accident.
That only works if permissions live with the data instead of sitting in a separate layer that runs last. Every record carries who can see it. Every query is made on behalf of a specific user. Retrieval resolves the two together and returns only what that user is already entitled to. The model works from the same view of the world the user would get if they searched by hand.
Post-filtering hides the answer after the fact. Permission-aware retrieval means the model never had the restricted data to begin with.
How this works when permissions live in the graph
"Move the check upstream" sounds simple. It usually isn't, because most stacks keep permissions in one system and the searchable index in another, so the two have to be reconciled by whatever code runs last.
In Curiosity, permissions are not a separate access layer. They are relationships in the same graph that holds the data. Documents, users, and teams are all nodes. Access is a path between them: a user belongs to a team, the team owns the record, so the user can see it. There is no second database of rules to keep in sync, because the rule is an edge in the graph.
Those edges are written when the data arrives, not after. If a source system already has its own permissions, they are mirrored at ingest time rather than reconstructed later. That timing matters: bolt ACLs on after indexing and you leave a window where the content is searchable but unprotected.
Enforcement then happens at query time, on every path into the data. When a user searches, the engine compiles that user's team memberships into an access filter and applies it before ranking, so restricted records never enter the candidate set. Direct fetches by ID go through the same check. And because the AI is grounded in that same filtered retrieval, the model is handed only what the user could already see. One rule, enforced in one place, for search, direct lookups, and AI answers alike.
It's a correctness problem, too, not only a security one
Leaks are the obvious risk. The quieter one is that ignoring permissions makes the AI wrong.
An assistant that retrieves across everything, for everyone, answers as if every user were an administrator. Ask it "how many open reqs does my team have?" and it counts reqs the asker can't see, so the number is confidently, precisely wrong. Ask "what's the status of the Acme deal?" and it summarises a version of the deal the asker isn't on, complete with a discount they were never supposed to know about. In both cases the answer reads as authoritative and describes a company the user doesn't actually work in.
Permission-aware retrieval fixes both problems with one mechanism. The user gets answers grounded in exactly the data they're allowed to use, which is also the only data that produces a correct answer for them. Security and accuracy turn out to be the same requirement seen from two sides.
What this looks like in practice
Getting this right means enforcing access in a few places that are easy to forget:
- At the field, not just the document. Sometimes a record is fine to see but one field on it isn't: a salary column, a customer's contract terms. Access control has to reach individual fields and record types, not just whole files.
- Everywhere data is read back. Not only the AI answer, but search results, facet counts, and autocomplete. A search that returns "0 results, 3 hidden" has told the user three things exist, so the filter has to apply before the count is computed, not after.
- On the tools the assistant can call. An assistant that can run actions needs those actions scoped too. A tool a user can't access should be invisible to their assistant, not merely refused when called, since a refusal still confirms the tool exists.
- With a record of what happened. When retrieval respects permissions, you can also prove it did: an audit log of who asked what, and what the system returned, turns "trust us" into something you can actually inspect.
None of this is exotic. It's the same access model the rest of the business already runs on, applied at the moment the AI reads data instead of after it speaks.
The takeaway
If you're evaluating an enterprise AI system, don't ask whether it "supports permissions." Almost everything claims to. Ask two things: where do the permissions live, and when are they applied. If they live in a layer bolted on top of the index, and they're applied as a filter at the end, the model is still reading things it shouldn't, and you're one prompt away from a leak that never shows up in a citation.
The version that holds up in production is the one where permissions live in the data layer itself and are enforced everywhere the data is read: search, facets, tools, and AI answers alike, resolved per user at query time. That's how Curiosity is built. Permissions live on the graph, retrieval resolves them for the person asking, and the assistant only ever sees what that person could see themselves.
Want to see how it works on your own data and access model? Talk to an engineer.
Referenced by
Read next
Articles on context graphs, enterprise search and industrial AI