An AI agent is only as trustworthy as the data access you give it. What permission-aware access for AI requires in a regulated firm, and how you prove that those controls worked.
A $3 billion registered investment adviser is rebuilding its technology stack. The appeal of an AI agent is simple. Instead of an adviser working through several systems and reports, they can ask a question and get the answer in real time.
The catch is that the most useful answers come from the most sensitive data. Tax details are the clearest example, and pointing an agent at them carelessly gives every adviser in the firm a query interface to every client's tax position.
So the chief compliance officer asks the right question, and usually the first one in the room: if we point this at our data, does it respect who is allowed to see what?
In most architectures shipping today the answer is no. Not because anyone was careless, and not because the technology is immature, but because of one design decision that most early deployments make without noticing.
Then you have row access policies and masking policies, and your access control sits in the database rather than in application code. That is the right architecture and it is ahead of where most firms are. The policies work. The question is which user they are evaluating, and for Snowflake there is one service that answers it differently from the rest. That is covered later in this paper.
Why the controls you already have do not travel with the agent.
An adviser asks the agent which of her clients have unrealised losses she could harvest before year end. The agent queries the warehouse for tax lot data.
The warehouse now has to decide what to return. It does not see the adviser. It sees whatever credential the agent used to connect, which in most deployments is a service account set up during the pilot. Her identity went as far as the agent and no further.
We call this identity collapse. Two people asking different questions arrive at the data as the same user, so the data gives them both the same answer. The permissions did not fail. They were never given the information they needed to work.
Security engineers call the general case a confused deputy. A trusted intermediary holds more authority than the person asking it to act, and cannot tell whose authority it is using. The agent authenticates to your systems with one high-privilege credential and uses it for every request from every user. It knows what is being asked but not who is asking, so it runs the request with its own privileges. The MCP specification names this problem directly, which is a good sign that it is not something vendors invented.
Nothing was done wrong here, which is what makes it awkward.
For thirty years, financial services software has kept access control inside the application. The portfolio system knows which advisers cover which households. The CRM has roles. Document management has folder permissions. The reporting tool filters before it renders. Each of these has a careful model of who may see what, and all of those models sit in application code.
The database underneath has almost always seen one connection from one application. It was never asked to make a decision about an individual user, because the application had already made it.
That worked while the application was the only way in. An agent is a second way in. It reaches the data directly and never touches the tier where the rules live.
Your permissions were never in the data. They were in your applications, and an agent does not go through your applications.
So "we already have access controls" is both true and not an answer. The controls exist. The agent does not pass through them.
Most firms running a pilot today have at least two of these.
The pilot needed to work. Scoping the connection to exactly what was needed would have taken weeks of entitlement mapping that nobody had budgeted for, so the agent was given broad read access with a note to tighten it later. The pilot worked and nobody went back.
In a documented 2025 case, an AI coding assistant connected to a Supabase project using the service_role key. Malicious text in a customer support ticket caused the assistant to run SQL the attacker supplied. Supabase pointed out afterwards that row-level security was never bypassed, and that the operator had chosen a credential designed to run above it. Both statements are true, and together they make the point: the server held one high-privilege identity, so per-user permissions had nowhere to attach.
This is the most common of the four and the least discussed.
When you build a retrieval system over documents, permissions are recorded at the moment each document is indexed and stored next to it. Queries then filter on that stored copy. It is a reasonable design, and it means that revoking someone's access may do nothing for a while.
Every major platform documents this. Microsoft says permission changes in the source system "are only reflected in search results after that metadata is synchronized to the index," and that SharePoint permissions inherited from a parent site "require an explicit refresh." Amazon says identity provider credentials are "cached for up to 1 hour" and that permission changes are "eventually consistent." Elastic runs content and access-control syncs on two separate schedules, which means two separate delays.
None of this is hidden and none of it is a defect. Read it as a compliance officer rather than an engineer and it means that between revoking access and the index catching up, the system will keep serving that person content they are no longer entitled to see. Most firms have never measured that window.
Retrieval ranks by similarity, not by permission. If one index covers every active matter, the agent will return the most relevant passage regardless of which side of a barrier it sits on. Under Advisers Act Section 204A the question is whether your controls were reasonably designed and whether misuse was foreseeable, not whether a trade happened, so the architecture itself is the finding.
Most firms have a folder that half the company can technically open and nobody ever has. That was survivable while finding anything required knowing it existed.
This one is usually described inaccurately, so it is worth being precise. When Microsoft 365 Copilot surfaced documents that users could technically but should not practically reach, Copilot was applying permissions correctly. It only ever touched content the user was authorised to see. The exposure was already there. AI assistants do not create over-permissioning. They make it easy to find.
Go back to the $3 billion adviser. Under any of the four failures above, the agent that helps one adviser harvest losses across her forty households is the same agent that will describe another household's tax position if the question is phrased slightly differently. Nobody has to be malicious for that to happen. Someone only has to be curious.
A working definition you can hold a vendor to.
"Permission-aware" is now used loosely enough that it has stopped meaning much. Here is a definition specific enough to test a vendor against.
Permission-aware data access means that every request an AI agent makes to firm data is checked against the permissions of the person it is acting for, at the moment of the request, inside the data layer, with the result recorded.
Five things follow from that, and you can test each one separately.
The data layer sees the person, not the agent. The agent should have its own identity too, but that answers a different question. Record both.
Not when the index was built, not when the connection was set up, not when the pilot was configured. This property removes the frozen index, and it is the one most architectures fail.
The filter is part of the query and the engine applies it before returning anything. It is not applied to the results afterwards by application code. Microsoft puts it in one line worth quoting to a vendor: "Authorization should always happen before retrieval, not after."
Filtering afterwards means the engine has already selected and returned content the user should not see, and correctness then depends on every piece of downstream code applying the filter, including code written next year by someone who has not read this. It is also unreliable on its own terms, because filtering after the top results are chosen can leave you with a partial or empty answer.
"You are not permitted to see the Hargreaves trust" confirms that the Hargreaves trust exists. Where a firm runs information barriers, the existence of a record is often the sensitive part. The agent should get a smaller set of results, not an error message about the rest.
If the first four hold and nothing was written down, you have a system that works and no way to show it. Part 4 covers that.
Permissions in a wealth or alternatives firm are not one rule. They work at three levels.
Row-level decides which records exist for this person. Our adviser sees her forty households. Her colleague sees his. The chief investment officer sees all of them.
Column-level decides which fields are visible, whatever records came back. An operations analyst may need to reconcile tax lots across the whole firm while never being entitled to see a full taxpayer identification number, a beneficial owner's date of birth, or adviser compensation. These are separate rules, and firms that implement only the first are often surprised by the second.
Masking covers the middle, where a value has to be present for a calculation but not readable in the answer. Last four digits, or banded rather than exact.
The third column in that diagram is worth a moment. A compliance officer usually does not need to read every client's tax position. They need to know who read it. Designing for that from the start avoids the common outcome where the surveillance function ends up with the widest data access in the firm.
It is tempting to handle permissions by telling the model about them. Put the adviser's client list in the system prompt. Tell the agent to refuse questions about other households. Add a filter that scans the output for names it should not mention.
All three are worth having and none of them is an access control.
A system prompt is an instruction to a probabilistic system, and an instruction you can argue with is not a control. More importantly, all three run after the data has been retrieved. The rows are already in the model's context, and whether it mentions them is a matter of behaviour. In a regulated firm the question is not whether the agent usually declines, but whether the data could be retrieved at all.
The MCP security documentation makes a similar point, listing as a common mistake "treating claimed scopes in token as sufficient without server-side authorization logic." Something on the server has to do the check, at the data.
If you want to know where your own stack sits against these five properties, we will walk through your architecture and tell you which ones hold today. No deck.
Book a demoWhat the standard gives you, stated honestly.
The Model Context Protocol is a published standard for how an AI assistant connects to a system that holds data or performs an action. Before it existed, every assistant and every system needed its own integration. MCP is one agreed shape, so anything built to it can connect.
It has moved quickly. The first widely used revision came out in November 2024, authorization arrived in March 2025, and the current revision is dated 28 July 2026. That version differs from what most vendor material still describes. It removed protocol-level sessions and deprecated the client registration mechanism that earlier guidance recommended.
MCP is a good thing. It is the reason connecting an assistant to a portfolio system now takes a week instead of a quarter. It is also a connection standard rather than a control framework, and it says so about itself.
Two passages are worth having in front of you when a vendor cites MCP support as a security feature.
While MCP itself cannot enforce these security principles at the protocol level, implementors SHOULD ... implement appropriate access controls and data protections. Model Context Protocol specification, revision 2026-07-28
And in the section covering tools, a requirement with no accompanying mechanism:
Servers MUST ... implement proper access controls. Model Context Protocol specification, tools, revision 2026-07-28
There is a mandatory requirement to implement access controls, and nowhere in the specification is there a model or a mechanism for doing it. That is a deliberate scope boundary rather than an oversight, and it is what this paper is about.
Put precisely: MCP defines authorization for scopes and tools. It says nothing about rows, columns or records.
| Question | Handled by the protocol | Your responsibility |
|---|---|---|
| Is this client who it claims to be? | Yes. OAuth 2.1, mandatory PKCE, mandatory protected resource metadata, strict audience validation. | Running an authorization server and connecting it to your real identity provider. |
| May this client call this tool? | Partly. Scopes, insufficient-scope challenges, step-up authorization, and tool lists that vary by the authorization presented. | Defining what your scopes mean and enforcing them on the server. |
| Which rows may this person see? | Nothing. Out of scope by design. | All of it. |
| Which columns may this person see? | Nothing. | All of it. |
| Whose authority is being used? | Warned about. Token passthrough is "explicitly forbidden" and the confused deputy problem is named directly. | Carrying the person's identity through to the data. |
| What was accessed, by whom, and when? | Nothing. No audit schema, no retention requirement, no logging obligation for servers. The diagnostic logging utility was deprecated in the current revision. | All of it. |
| Does any of this apply to a server on a laptop? | No. Implementations using stdio transport "SHOULD NOT" follow the authorization specification and instead "retrieve credentials from the environment." | Everything, and this is the most common way MCP is deployed. |
That last row matters more than it usually gets credit for. The local server is not an edge case. In one analysis of more than 15,000 deployments, 86% ran locally and 95% ran on employee machines. The most common way MCP is deployed is the way the authorization specification does not cover.
In June 2026 the OpenID Foundation's AuthZEN working group approved a draft called "AuthZEN Profile for Model Context Protocol Tool Authorization," which maps MCP into an explicit subject, action, resource and context model so that external systems can make the decisions MCP does not. Separately, an IETF individual draft on AI agent authentication proposes using OAuth token exchange to carry delegation. Neither is ratified. Both exist because the gap is real, and both are being built outside the MCP specification rather than inside it.
An MCP server is easy to run, which is mostly a good thing.
It also means that any capable person in your firm can connect an assistant on their laptop to a production system using credentials they already hold. No procurement, no architecture review, no ticket. They are not doing anything malicious. They are being productive, which is why it spreads.
What you end up with is a path to your data that appears in no access review, writes to no log you can query, and is in no inventory. The permissions are whatever that individual happens to hold, which for a senior engineer is usually a lot.
OWASP added Shadow MCP Servers to its MCP Top 10 as MCP09:2025, defining them as "unapproved or unsupervised deployments of Model Context Protocol instances that operate outside the organization's formal security governance," and listing regulatory noncompliance and problems with incident response among the impacts.
The first control here is not technical. It is an inventory. You cannot govern connections you cannot list, and the survey figure above suggests four firms in five have no current view of what is connected.
The answer is simple to describe and real work to build. Every agent request to firm data goes through one entry point, which does five things in order.
Against your existing identity provider. The person, not the agent, and not a service account set up during a pilot.
Reads current group membership and current book of business at the moment of the request. Nothing cached from indexing.
The agent asks a business question against a governed model. It does not get raw tables and decide for itself what to select.
Row and column rules become part of the query. The engine never returns what it should not.
Who asked, resolved identity, policy version, what was requested, what came back, what was withheld.
The third step carries more weight than it looks. If you hand an agent raw tables, every question of what can be selected, joined and aggregated has to be settled at query time by policy alone, against a query the agent wrote itself. If instead you give it a governed model of the business, with defined entities, relationships and measures, the surface area is bounded before policy is consulted at all.
The reason to insist on one entry point is practical. The number of places you have to get this right stays at one as the number of agents grows. A firm running six assistants through six integrations has six permission models to keep in step with reality, and it will not.
The part an examiner actually asks about.
An examiner will not ask whether your architecture is sound. They will ask you to show them. Which of your people had access to this client's information in the second quarter. Show me that this analyst could not reach that deal file after they moved teams. Explain why this number appeared in this client report.
You can only answer those questions if the system wrote something down at the time. Reconstructing them afterwards from architecture diagrams and policy documents is not evidence, and everyone in the room knows it.
The regulatory direction is clear enough. The SEC's 2026 examination priorities do not treat AI as a separate item. They thread it through cybersecurity, emerging technology, automated investment tools and operational resiliency, so AI oversight forms part of most examinations rather than a special one. FINRA's 2026 report, in its section on generative AI, discusses monitoring that "may include storing prompt and output logs for accountability and troubleshooting," along with tracking model versions and human review of outputs. That is practice guidance rather than a rule and should be described that way, but the direction is not ambiguous.
The MCP specification makes the same argument from another angle. Explaining why token passthrough is forbidden, it warns that the downstream system's logs "may show requests that appear to come from a different source with a different identity," which makes "incident investigation, controls, and auditing more difficult."
MCP defines no audit schema, no retention requirement and no logging obligation for servers. That is left to you. Here is a schema you can adopt whoever you end up buying from.
Two fields do most of the work and are the two most often missing.
Policy version. Permission rules change. Advisers move books, analysts change teams, a household gets restricted. If the record does not say which version of the rules applied at the time, you can show what the system returned but not that it was right to return it.
What was withheld. Almost everyone logs what came back. Very few log what was filtered out. But showing that the controls worked is a statement about what did not cross, and a log of successes alone cannot support it.
Take the awkward version. It is March, and an examiner asks about a tax projection that appeared in a client's June review. They want to know how it was produced and whether the adviser was entitled to the inputs.
With the record above it is mechanical. You retrieve the request, see the person and the agent, see which entities were touched, see the policy version and pull the rules as they stood in June rather than as they stand now, see the filters that were applied, and see what was returned and what was withheld. It takes minutes and it holds up, because it was written at the time.
Without it you are reasoning from the current state of a system that has changed since, in front of someone whose job is to notice that.
One more problem is worth naming, because agents make it worse.
Every individual query can be permitted while the total is not. An analyst entitled to see aggregate exposure by sector, vintage, geography and manager can, with enough well-formed questions, work out a position they were never entitled to see directly. Nothing in the row-level model is broken. The controls worked on every request and the information still got out.
This is not new and it is not an AI problem. It has a name and a standard reference going back nearly forty years.
The aggregation problem arises whenever some collection of facts has a classification strictly greater than that of the individual facts forming the aggregate. Teresa F. Lunt, "Aggregation and Inference: Facts and Fallacies," IEEE Symposium on Security and Privacy, 1989
What agents change is the cost. Building that chain by hand across twenty queries was tedious enough to be self-limiting. An agent will do it in a paragraph, because it was asked a reasonable question and it is trying to help.
We are not going to claim this is solved, because nobody has solved it. What we would say is that a firm with the record in Figure 8 can at least spot the pattern afterwards and set thresholds. A firm without it cannot.
Questions to ask, and a sequence to follow.
Use these in a diligence call. They are ordered so that a vendor who cannot answer the first four will not get to the fifth. The honest ones tend to welcome them, because the questions separate a real architecture from a demonstration.
None of this requires a platform decision first, and the order matters more than the speed. Firms that start at step three because it is the interesting one usually end up redoing it.
One note on step one. The inventory is not a technology project and it will be uncomfortable. Ask your engineers what is running locally, and make it clear the answer carries no consequence. You want to know what is true, not who is at fault. Firms that treat the first inventory as a disciplinary exercise get a clean list and a false picture.
Everything above can be built by any firm with the engineering capacity to do it. This section is what we built, because describing a problem without saying what you do about it would be coy.
Clarista sits between the consumers and the data as the single entry point in Figure 7. Three decisions do most of the work.
The model is the interface, not the table. Agents connect to a governed model of the business with defined entities, relationships and measures. Raw tables are not exposed. This bounds what can be asked before policy is consulted, and it means the same controls serve an adviser assistant, a notebook, a BI tool and a coding agent, instead of each one getting its own integration.
Access is checked, not granted. The user's identity comes through from your identity provider and permissions are checked at the moment of the request. Row and column rules become part of the query and the engine applies them. Nothing is cached from indexing, so revoking access takes effect on the next request rather than the next sync.
The data stays yours. The lake and the infrastructure are yours. We govern access to them and we do not host them. If you leave, you keep the data, the model definitions, the policies and the access records. That is the tenth question in the list above, and we think you should ask it of everyone.
For the firm this paper opened with, the result is that the tax integration became possible instead of being deferred indefinitely. The agent can work with tax lots because the adviser asking is resolved to her forty households before the query runs, taxpayer identifiers are masked for the roles that do not need them, and every request can be replayed. The data is no less sensitive than it was. What changed is that every request is checked against the permissions of the person asking, and every check is recorded.
Clarista holds SOC 2 Type II attestation and ISO 27001 certification. Neither of those answers the ten questions above, and we would encourage you to ask them of us in exactly the form you would ask anyone else.
This section is for the reader who has invested in a modern warehouse and reasonably believes per-user access is handled. Much of it is.
Row access policies and masking policies put access control in the database, below the application, where prompt injection and a mis-scoped agent tool cannot reach it. That is a better position than an application-tier permission layer, and it fails safely: a bug produces fewer rows rather than more. If you have done this, the database half of the problem is done properly.
What remains is which user the policies evaluate against.
Snowflake describes column-level security as depending on "the current session," with masking conditions written against CURRENT_ROLE, and recommends IS_ROLE_IN_SESSION for row access policies where role hierarchy matters. CURRENT_USER returns the name of the user logged into the system. All of that means the authenticated principal, and an application has no way to tell the database that a different human is behind the request.
So if your agent connects with a service user, every policy evaluates against the service user and returns exactly what it was asked for. Databricks works the same way. Unity Catalog row filters and column masks run with definer's rights except for the functions that check user context, such as session_user and is_account_group_member, which run as the invoker. Connect as a service principal and those resolve to the service principal.
One point of confusion is worth clearing up, because it looks like it contradicts the above. Snowflake's documentation says it "evaluates the policy expression by using the role of the policy owner, not the role of the operator who executed the query." That is about privileges on the mapping tables inside the policy body, so that a querying user does not need SELECT on them. The context functions still return the querying session's identity.
This is the part worth checking in your own account.
Cortex Analyst generates SQL that executes in the caller's session, and Snowflake states that queries it generates "adhere to all established access controls." Cortex Search, the retrieval service, is documented differently:
Cortex Search Services perform searches with owner's rights and follow the same security model as other Snowflake objects that run with owner's rights. Snowflake documentation, Query a Cortex Search Service
To query a Cortex Search service a user needs USAGE on the service, the database and the schema. They do not need SELECT on the tables underneath. The index was built under the creator's privileges, so results reflect the creator's view of the data rather than the caller's. Snowflake's own documentation adds: "Use caution, for example, when granting a role with USAGE privileges on a Cortex Search Service to another Snowflake user."
The practical consequence for a wealth or advisory firm is that the structured half of an agent can be correctly filtered per user while the document retrieval half, which is where client correspondence, agreements and memos live, is not.
Cortex Agents reads the default role, not the active one. Snowflake documents that Cortex Agents "determines session permissions from the querying user's default role, not the role active in their session." Firms that implement least privilege by having people switch into a narrower role get no benefit from that here, because the default role is usually the broadest one they hold.
Owner's rights procedures drop the caller's context. Wrapping data access in a stored procedure is a normal way to expose a tool to an agent. An owner's rights procedure "cannot access most caller-specific information," and INVOKER_ROLE inside one resolves to the procedure owner. A masking policy written against INVOKER_ROLE then evaluates against the owner. No error is raised.
Snowflake now ships an explicit machine identity for agents. The SERVICE_AGENT user type became generally available in July 2026, for agents that interact with Snowflake, in Snowflake's words, "using their own identity and privileges." There is also an IS_AGENT_ACTIVATED function so you can write policies that tighten when an agent is in the session. Both are useful. Both tell you that an agent is acting, and neither tells you who it is acting for.
Being fair about this matters, because the answer is not that the warehouse is inadequate.
If each person authenticates to Snowflake individually through your identity provider using External OAuth, so that CURRENT_USER is the human, and your policies are written on CURRENT_USER or IS_ROLE_IN_SESSION, and your tools are caller's rights or direct SQL, then per-user enforcement works correctly for the synchronous query path. Snowflake CoWork documents exactly this model: "All of the queries from Snowflake CoWork use the user's credentials. All role-based access control and data-masking policies associated with the user automatically apply."
What tends to break that pattern is not configuration error. It is the shape of agent architectures.
Snowflake's query result cache is worth a test rather than an assertion. Snowflake documents that result reuse requires the role accessing the cached result to have the required privileges, and that privilege check is described at object level. We could find no public documentation of how the result cache interacts with row access or masking policies in either direction. If you depend on the cache, verify the behaviour empirically in your own account and record what you find, because an undocumented control is itself something to write down.
None of this reduces the case for putting access control in the database. It is where it belongs. The gap is that agent architectures routinely create execution contexts with no human session attached, and that is the part a governed entry point has to solve before the query ever reaches the warehouse.
Give the agent no standing credential of its own. Route every request through a governed layer that resolves the asking user’s identity, applies that person’s row and column permissions at query time, masks PII before the model sees it, and writes a per-query record of who asked, what ran, and what came back.
Not at the level that matters for client data. MCP defines authorization for scopes and tools, using OAuth 2.1. It says nothing about rows, columns or records. Its own specification tells implementers to build access controls and provides no mechanism for doing so. Treat MCP as a connection standard and supply the permission layer yourself.
Yes, in most current architectures, and usually by accident. If the agent connects using a shared service account, the data layer never learns which person is asking and applies the agent's permissions rather than theirs. The fix is to carry the user's identity through to the data and check permissions when the question is asked.
Filter inside the retrieval engine as part of the query, never on the results afterwards. The wider problem is that most retrieval systems record permissions when a document is indexed rather than when a question is asked, so revoking access does not take effect until the next sync. Ask your platform to state that window in writing and treat it as a measured control gap.
An MCP server running outside your governance, usually on an employee's machine, connected to a real system with that individual's own credentials, the same exposure class we map in our AI agent governance whitepaper. OWASP lists it as MCP09:2025 in its MCP Top 10, defining it as a deployment that operates "outside the organization's formal security governance." It appears in no access review and produces no audit trail you can query.
Yes, and it is not enough on its own. Agent identity tells you which agent acted. It does not tell you whether the person it acted for was entitled to the data, which is the question a regulator asks. Record both, and the delegation between them. Standards work is active but nothing is ratified: an IETF individual draft proposes using OAuth token exchange for delegation, while the Cloud Security Alliance argues existing scope-based models are not adequate.
It is necessary and not sufficient. You also need column-level enforcement, because entitlement to a record is not entitlement to every field on it, and you need a plan for aggregation, where individually permitted queries combine into an answer that is not. Row-level security works correctly throughout an aggregation exposure, which is why the only practical control there is watching the access record.
At minimum: the person, the agent identity and version, the delegation between them, the question and the query it became, the entities and fields touched, the policy version in force, the filters applied, what was returned, and what was withheld. The last two are usually missing, and without them you can show what the system returned but not that it correctly withheld everything else.
You can, and it is worth doing as one layer among several, but it is not an access control. Prompt instructions and output filters run after the data has been retrieved into the model's context. The question in a regulated firm is not whether the agent usually declines, but whether the data could be retrieved at all.
Choose which categories of cookies and tracking technologies you allow. Strictly necessary cookies cannot be disabled. Read our full Cookie Policy.
Required for security, authentication, fraud prevention, load balancing, and storing your consent preferences. Always on.
Remember choices you make to provide a personalized experience (language, region, theme, saved filters).
Help us understand how the site is used (Google Analytics, Vercel Analytics, Microsoft Clarity, etc.).
Used for conversion tracking, retargeting, and personalized ads (LinkedIn, Meta, Google Ads, Bing, etc.).