How do you stop an AI agent from being overprivileged on a Databricks MCP or Genie connection?
Five steps, in sequence.
- Short-lived, single-audience tokens. Use the RFC 9068 JWT access-token format. Pin an
audclaim to one MCP server. Require the RFC 8707resourceparameter too. Then a Genie token cannot be replayed against your SQL warehouse. - Token exchange over passthrough. Say the agent's identity must reach a downstream API. Swap the token via RFC 8693 token exchange. The downstream then sees a scope-narrowed credential, correctly audienced. Not a borrowed user token.
- Least privilege, then step up. Start with the smallest scope the task needs, always. Ask for more only after a 403. Do not grant broad scope up front. It is easy. It is not safe.
- Per-call authorization. Check what the agent may do on each call. A revoked grant then dies on its next call. Not at token expiry.
- Untrusted tool text. Treat each tool description and output as hostile input. It lands in the model. With ambient power. No sanitizing.
Databricks native governance covers part of this. What it skips, per the public docs? A per-call ceiling. Or a next-call kill. The rest of this post explains why that matters, and how to close it. Read it as an engineering threat model. Not a full compliance checklist.
What "overprivileged" actually means on an MCP connection
An agent is overprivileged when its token reaches too far. More than the task needs. More tools, or more data. Worse, that power just sits there all session. Say you ask Genie one question about last quarter's churn. Say the connection scope is broad. That same session can now read every table the scope touches. Nothing narrows after the first answer.
The MCP Authorization spec is honest about where it stops. It makes authorization optional. It sets the MCP server as an OAuth 2.1 resource server. That means the server checks tokens issued by a separate login server. It sets no per-tool-call ceiling. So the standard gives you one clean check. Is the token valid, and correctly addressed? It says nothing about re-checking power mid-task. Session-long power is the default. That default is what an attacker gets. The moment they hijack the agent's goal, it is theirs too.
What the MCP Authorization spec requires, and what it leaves out
Two rules in that spec matter most. I see people skip both.
Audience binding is mandatory. The spec says MCP servers MUST check one thing: Was a token issued for them, as the intended audience? Per RFC 8707. MCP clients MUST NOT send tokens from anywhere else, only ones issued by the server's own login server. Servers MUST NOT accept or pass on any other token. That is the spec ban on token passthrough. And passthrough creates confused-deputy risk. Say your Databricks MCP server forwards any bearer string it sees. You just built the confused deputy yourself.
Resource indicators are mandatory. Clients must build RFC 8707. The resource parameter must appear in the authorization request. And the token request. It names the server by its own URI. One token, one target.
The gap matters most. Scopes stay coarse: files:read, files:write. They get set once, at issuance. The step-up flow lets a client ask for more scope, after an HTTP 403 insufficient_scope. That part works well. But nothing re-checks scope per call. The spec is a living document, dated by revision. These audience and no-passthrough rules have held since the June 2025 revision. They predate this post by a year. The clause numbers may shift as it gets revised. The rule itself has held.
What Databricks native governance gives you (and what it doesn't)
Databricks announced managed MCP servers, with Unity Catalog integration, in June 2025. The managed set covers Genie (scope genie), AI Search (ai-search), Databricks SQL (sql), and Unity Catalog functions (unity-catalog). On-behalf-of-user login comes out of the box. The docs put it plainly: "Unity Catalog enforces permissions, so agents and users access only the tools and data you grant them." That is good hygiene. You should use it.
Register an MCP server as a Unity Catalog securable. Admins then get four things. Grants say who can invoke it. Tool selection sets which tools it exposes. Service policies allow, deny, or approve single calls. Plus audit logs. Unity AI Gateway adds runtime flow and behavior rules. Across models, agents, servers, and tools alike. It also handles OAuth token exchange, and refresh. On-behalf-of token passing runs behind the scenes.
Here is the edge worth naming: what those grants skip. They scope by role, permission, and tag. Service policies act at the grant layer. The documented model skips a per-call scope ceiling. One re-derived on each tool call. Nor does it cover mid-session, next-call token kill. Tokens just expire on their own clock. I am not saying Databricks cannot do these things. I am saying the public docs do not cover them. And any agent outside the Gateway runs ungoverned, full stop. Check the newest docs first.
The threats: tool poisoning, the lethal trifecta, and real incidents
In April 2025 Simon Willison named the core problem. Combine private data, untrusted content, and a way out for stolen data. Any tool acting on the user's behalf becomes attacker-controllable. As he put it, "you're effectively allowing attackers to make those tools do whatever they want." He later named that combination the "lethal trifecta." The Invariant Labs WhatsApp MCP attack he covers steals message history. He notes an attacker can even base64-encode it, to hide the theft. He also notes the field still lacks a good fix for prompt injection. Even after years of trying. A Databricks MCP connection carries all three, by design.
Keep the incidents below straight. The labels get mixed up.
- EchoLeak (CVE-2025-32711) was proof-of-concept research. Not a real-world breach. Disclosed by Aim Labs in June 2025, at CVSS 9.3. It was a zero-click prompt injection in Microsoft 365 Copilot. One crafted email. No clicks needed. Copilot could read internal files, and leak them. Microsoft patched it server-side. No confirmed exploit in the wild. OWASP lists it among its ASI01 Agent Goal Hijack examples.
- MCPoison (CVE-2025-54136) came from Check Point Research. Disclosed in early August 2025. Cursor approved an MCP config once, then stopped re-checking it. So an attacker with write access to a shared repo could swap that config. For a bad one. Then keep code execution, persistent. It was fixed on July 29, 2025, in Cursor 1.3. That version re-prompts on any config change.
- AgentFlayer was shown by Zenity at Black Hat USA, in 2025. It chained zero-click and one-click prompt injection, against enterprise agents. That included secrets stolen through a Jira MCP server in Cursor. This too was just research. A live proof the chains work, outside a slide deck.
- Tool poisoning is now its own documented class. Bad instructions hide in tool descriptions or MCP systems. The model reads them with full ambient power, and no filter. Definitions can also change after approval.
One thread runs through each case. Trust set at connect time does not hold at run time. OWASP's Top 10 for Agentic Applications, published December 9, 2025, ranks Agent Goal Hijack (ASI01) first. It lists Identity and Privilege Abuse (ASI03) as its own class. That puts overprivilege squarely on the list.
Databricks MCP security best practices: how to prevent overprivilege
A few concrete moves, roughly in the order I would apply them. Issue RFC 9068 JWTs with an aud bound to a single server. Add the RFC 8707 resource parameter to each authorization and token request. Then a stolen Genie token is worthless against your SQL warehouse. Reject any token your MCP server did not get from its own authorization server. Give downstream calls an RFC 8693 exchange. It narrows scope and re-audiences the token. No borrowed bearer string ever passes through. Advertise only the scopes you actually need. Let the client escalate after a 403. Do not front-load broad session scope to save a round trip.
Then re-check trust at run time. MCPoison worked since approval was a one-time event. So re-prompt or re-authorize on any config or tool-definition change. Check the OAuth iss (RFC 9207) and state on each callback, to blunt mix-up and confused-deputy attacks. Never let tool text steer the agent unchecked. Finally, limit the blast radius in the data plane. Assume some prompt injection lands. Ask what the agent can actually reach when it does.
That last question is where native grants and a per-call authorization layer stop overlapping. For the wider attack surface, see the sibling MCP server security threat model. It walks each class and its control. MCP prompt injection covers the injection half in depth.
The data-plane angle: what the agent can physically reach when a control fails
Each control above governs what the agent is allowed to do. The other half is what it can physically reach when a control fails. That is the layer most MCP guides never touch.
Tokenize sensitive fields at ingest. Say PII becomes a token at the point of storage. A hijacked agent that slips past each authorization check then pulls back tokens. Not raw Social Security numbers or account balances. The exfiltration in an EchoLeak-style attack then walks off with ciphertext-shaped noise. This complements Unity Catalog. It does not replace it. Unity Catalog governs who may invoke a tool. Field-level tokenization limits what the pulled data is worth, once it leaves the edge. DataShield builds this as a proof-and-authority layer around your warehouse. An encrypted connection vault holds the credentials. The agent never touches raw warehouse secrets. The ontology is where you declare which fields count as sensitive. That comes first.
The practical stance: native governance has to cover reach as well as intent. Tokenization is what makes a breach of that governance survivable.
Databricks MCP server authorization and proof it happened
The missing piece under the Databricks model is a ceiling. One re-derived on each tool call, plus revocation that bites at once. DataShield Auth does that, as a per-call dispatch pipeline. For each call it applies a scope ceiling. Next, a power tier check. Then a mid-session revocation re-check. Metered dispatch follows. Then a sealed, hash-chained audit entry. The effect is the one that matters during an incident. A token stolen at 9:00 is dead at 9:05. Killed on the very next call, not whenever it would otherwise expire. Delegation runs on-behalf-of, with the same scope ceilings. A sub-agent can never exceed the power of the agent that spawned it.
Worth a note on where policy engines belong, since it trips people up. Cedar-style policy fits admin, platform, config, and token calls well. It is not the per-tool dispatch system. That job belongs to the dispatch pipeline. Mix the two layers and you end up re-reading a policy document. On a hot path. Calling it authorization.
Auditors and incident responders will not take your word for it. So each call seals into a tamper-evident, hash-chained record you can verify after the fact. Someone asks which agent read which table at 9:03? You have a cryptographic answer. Not a log you hope is complete. To be straight about the limits: this is DataShield's described feature set. There is no SOC 2 attestation yet; it is planned, not attested. Check it on its engineering merits and confirm the claims yourself.
Watch: related explainers
Two walkthroughs of MCP on Databricks. Genie, plus how to vet an MCP server.
Frequently asked questions
Does Databricks Unity Catalog already stop an agent from being overprivileged?
It helps, though not all the way. Unity Catalog and Unity AI Gateway govern who can invoke an MCP server. And which tools it exposes. They can also allow, deny, or approve single tool calls. All scoped by role, permission, and tag. Per the public docs, that model does not re-derive a per-call scope ceiling. Not on each call. It does not kill a token on the next call after revocation. Tokens simply expire on their own schedule. Treat native governance as the needed base. Then add per-call authorization on top.
What is token passthrough and why is it dangerous on an MCP server?
Passthrough is when an MCP server forwards any bearer token it gets. On to a downstream API. Instead of checking and exchanging it. The MCP Authorization spec forbids it. Servers must check that tokens were issued for them as the intended audience (RFC 8707). They must not accept or pass on any other token. Passthrough creates confused-deputy risk. The server uses its own trust to act on an attacker-supplied credential. Exchange tokens via RFC 8693 instead.
What's the difference between least-privilege scope and per-call authorization?
Least-privilege scope gets set once, at token issuance. It can be stepped up after an HTTP 403 insufficient_scope error. Between those events, though, it stays fixed for the session. Per-call authorization re-derives what the agent may do, on each single tool call. A revoked grant then dies mid-session, on the next call, not at token expiry. The MCP spec standardizes the scope negotiation. It leaves per-call authorization for you to build.
Was EchoLeak an actual breach of Microsoft 365 Copilot?
No. EchoLeak (CVE-2025-32711, CVSS 9.3) was proof-of-concept research, disclosed by Aim Labs in June 2025. It was a zero-click indirect prompt injection. It could make Copilot read and exfiltrate internal files. Microsoft patched it server-side and reported no confirmed exploitation in the wild. OWASP lists it among its ASI01 Agent Goal Hijack examples. It showed the system at work. No real-world compromise stood behind it.
How does field tokenization help if my agent still gets hijacked?
It limits the blast radius. Say sensitive fields are tokenized at ingest. An agent that slips past authorization and exfiltrates data walks off with tokens. Not raw PII. The stolen payload is worthless without the separate detokenization power. It complements Unity Catalog access control. It does not replace it. The access grant governs whether the agent may act. Tokenization governs how much a stolen result is worth, once it crosses the boundary.