Cortex agents run with the full authority of the role that invokes them, so securing Cortex is a data-layer access problem, not a model problem.
Cortex agents are not a separate security boundary. They execute under the caller's role and inherit every grant that role holds, which is why an agent can read a table the person asking never had access to. - The real question is not what a Cortex agent is configured to do. It is what its execution role actually resolves to inside Snowflake once inherited roles, future grants, and object ACLs are computed. - The riskiest setup is a service account with broad SELECT, or worse DROP TABLE, wired into a Cortex Analyst or Agent and then exposed to a wide audience. - Native Snowflake auditing shows that a query ran under a role. It does not show which agent invoked it, on whose behalf, or whether the effective access exceeded the invoker's own permissions. - Around 90% of agent identities run over-permissioned, and agents move data at machine speed, so a single over-scoped Cortex role is a standing liability, not a one-time misconfiguration. - Governing Cortex today means discovering every agent and mapping its effective access to real grants, then correcting the toxic combinations before they matter.
Snowflake Cortex security starts with one fact that reframes everything else: a Cortex agent has no identity of its own. It executes under the Snowflake role of the session that invokes it, and every function call, warehouse query, and semantic model lookup runs with that role's grants. The agent is the role. Whatever the role can touch, the agent can touch.
This matters because most teams wire Cortex Analysts and Agents to a service account for convenience. That service account often carries broad SELECT on shared schemas, USAGE on more than one warehouse, and sometimes OWNERSHIP or MODIFY on tables that were meant to stay read-only. The moment a business user asks the agent a question, the agent runs with the full authority of that service account, not the user's own role.
Here is the mechanism in plain terms:
FINANCE.REVENUE opens a Streamlit app powered by Cortex Analyst.SELECT ON ALL TABLES IN SCHEMA FINANCE.This is the same maker-mode pattern that appears in other agent builders, translated to the data warehouse. The control that matters is not the model or the prompt. It is the identity the agent borrows and the effective access that identity carries.
The blast radius of a Cortex agent equals the union of every grant its execution role holds, including everything it inherits through the role hierarchy. Grant SYSADMIN to a Cortex service role for a quick proof of concept, forget to revoke it, and that agent can drop any table in the account.
Consider a pattern that shows up again and again:
| Configuration | Intended use | Actual blast radius |
|---|---|---|
Service role with SELECT on ANALYTICS.* |
Answer BI questions | Reads all analytics data, including PII columns |
Same role also holds USAGE on PROD_WH |
Run queries efficiently | Burns production credits with no quota control |
Same role granted SYSADMIN during setup |
Deploy the agent | Can DROP TABLE, DROP SCHEMA, and CREATE anywhere |
| Agent exposed via Streamlit to all staff | Self-service analytics | Every employee now executes as SYSADMIN |
The service-account-with-DROP-TABLE case is not hypothetical. A Cortex agent that inherits a privileged role can be steered, through ordinary natural-language questions or through instructions planted in the data it reads, into running destructive SQL. Publicly reported incidents where an AI coding agent deleted a production database show the same shape in a different environment. In Snowflake, the guardrail is role isolation, not model tuning. If the role cannot drop the table, no prompt can make the agent drop it.
You cannot govern what you cannot see, and Cortex usage hides. It lives inside Streamlit apps, notebooks, custom applications calling COMPLETE() or EXTRACT_ANSWER(), and Cortex Analyst semantic models scattered across schemas. Discovery is step one, and it has two halves.
Where to look inside Snowflake:
SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY, filtered for SNOWFLAKE.CORTEX function callsSNOWFLAKE.ACCOUNT_USAGE.CORTEX_FUNCTIONS_USAGE_HISTORY for token and function-level usageSHOW STREAMLITS IN ACCOUNT.yaml files that define a Cortex AnalystWhere Cortex usage hides outside Snowflake:
The gap most teams hit is attribution. Native audit tells you a query ran under a role. It does not tell you which agent, which semantic model, which downstream application, or which end user triggered it. Discovery that stops at "a Cortex function was called" leaves you with a count, not an inventory. What closes that gap is correlation: tying each Cortex call back to the specific agent, the service account it borrowed, and the tables and actions that call actually reached.
The documented scope of a Cortex agent is what its designer wrote in a spec or a semantic model YAML. The effective access is what its role resolves to inside Snowflake after every inherited role, future grant, and object ACL is computed. These are rarely the same, and the difference is where risk lives.
Two agents can share the same stated purpose, "answer sales pipeline questions," and carry very different effective access:
SALES_ANALYST_AGENT with SELECT on SALES.PIPELINE_VW only. Effective access matches the documented scope.SALES_AGENT_SVC, which inherits ANALYST_ROLE, which inherits DATA_READER, which holds SELECT ON ALL TABLES IN DATABASE PROD. The spec says "pipeline only." The effective access includes HR, finance, and customer PII.Auditing Cortex means computing that resolution for every agent, and recomputing it as things change. Role hierarchies get edited. GRANT SELECT ON FUTURE TABLES adds access silently. A schema added to PROD last week is readable by Agent B today, without anyone approving it. Reading the vendor's configuration page tells you the theoretical scope. Only the resolved grant path tells you the truth, and only correlating that path with what the agent actually queried tells you whether the access is being used.
A single risk factor on a Cortex agent might be medium severity. Stack two or three and the picture turns critical fast. These toxic combinations are what a security team should rank first, because they concentrate the damage.
High-priority combinations for Cortex:
SYSADMIN or ACCOUNTADMIN, plus exposure to all staff via StreamlitSELECT on PII tables, plus no dynamic data maskingCOMPLETE() calls sending sensitive column data, plus no masking policy on the source columnsThat last item is the machine insider problem in Snowflake form. When five agents share CORTEX_SVC_ROLE, the audit log shows the role ran a query. It cannot tell you which agent ran it, or on whose behalf. The fix is not more log volume. It is correlation that pins each query to a specific agent identity, the service account behind it, and the objects and actions it touched, so a toxic combination is visible as a single finding instead of five anonymous rows.
Governing Cortex means enforcing least privilege at the role, warehouse, and object level, then verifying continuously that effective access still matches intent. Configuration drifts on its own. The check that holds up is runtime truth: what each agent actually did, not what its spec claims it should do.
A practical governance baseline:
SYSADMIN or a shared analyst role.SELECT on specific views, not on schemas or databases. Keep FUTURE GRANTS off Cortex service roles.USAGE on a small, monitored warehouse with a resource monitor and a credit cap.QUERY_HISTORY with application logs so every Cortex query traces to a person, not just a service role.Snowflake's native controls make each of these possible one at a time. What native tooling does not give you is a single view of which controls are missing across hundreds of agents, or which agent's effective access has outgrown its documented scope. That is the work Obsidian does for Cortex today: continuous discovery of every Cortex agent and non-human identity, a resolved map of effective access against real grants, and the toxic combinations ranked so you fix the ones that matter. It correlates each agent's runtime activity to the service account and the tables and actions it reached, which turns an audit log into an authority map. This runs from the account metadata Snowflake already exposes. It does not sit inline and it does not proxy your data path.
Autonomous runtime enforcement, where a decision engine blocks a Cortex agent's action in the moment, is on the roadmap for platforms like Cortex, not shipping today. It follows an "Intel Inside" model where Obsidian supplies the access and behavior intelligence to a decision point rather than becoming an inline gateway. For Cortex right now, the durable wins come from discovery, effective-access mapping, and least-privilege governance, which remove the blast radius before an agent can act on it.
Cortex runs inside Snowflake's existing RBAC, encryption, and network-policy boundary. Data is encrypted at rest and in transit under the same model as any other Snowflake workload. The variable that determines exposure is the role: Cortex functions, Analysts, and Agents can only touch what the invoking role is granted, so authorization, not encryption, is where the risk concentrates.
Because the agent executes under the role of the session or service account that invokes it, not the end user's own role. If a Streamlit app authenticates with a service account that has broad SELECT, every user of that app inherits that access for the duration of their question. The agent borrows the service account's effective access, which is often far wider than the user's.
Start with QUERY_HISTORY and CORTEX_FUNCTIONS_USAGE_HISTORY for Cortex function calls, SHOW STREAMLITS IN ACCOUNT for apps, semantic model YAML files in stages, and the service users created for agent auth. The harder part is attribution: correlating each call back to a specific agent, the service account it used, and the objects it reached, rather than a raw count of Cortex queries.
The documented scope is what a spec or semantic model says the agent should do. The effective access is what its role actually resolves to after inherited roles, future grants, and object ACLs are computed. An agent scoped "pipeline only" on paper can hold SELECT across an entire production database through role inheritance. Only the resolved grant path, checked against actual queries, shows the real picture.
Create a dedicated role per agent, grant SELECT on specific views rather than schemas, scope each role to a small capped warehouse, and apply masking and row-access policies on sensitive columns. Avoid inheritance from SYSADMIN or account-wide reader roles, and rotate key-pair credentials on a fixed cycle. Least privilege here is per-agent, not per-team.
Not today. For Snowflake Cortex, Obsidian discovers every agent and non-human identity, maps effective access against real grants, and surfaces toxic combinations so you can correct them. Autonomous runtime enforcement for platforms like Cortex is on the roadmap and follows an "Intel Inside" decision-engine model rather than an inline gateway. The present-day value is removing over-permissioned blast radius before an agent can act on it.