Author: Christopher Emerson

  • MCP Security: How to Let an AI Agent Access User Data Safely

    Short answer: MCP standardizes how an AI agent discovers and calls your tools and data, and it added an OAuth-based authorization framework to go with it. What it does not give you on its own is per-agent, scoped, revocable access that the end user controls. To let an agent access user data safely through MCP, add a layer of user-mediated authorization: the user approves specific scopes, the credential is delivered to the user rather than pushed to the agent through an automated channel, and every call is checked against that grant. MCP handles what the agent can see. User-mediated authorization handles whether it is allowed.

    What MCP handles, and what it leaves to you

    The Model Context Protocol solved a real problem: a common way for agents to find tools, read resources, and call them across different systems. Its authorization spec is OAuth-based and is getting stricter. The protocol’s 2026-07-28 revision hardens authorization with six changes, including issuer validation per RFC 9207 and cleaner dynamic client registration.

    But a protocol that standardizes authentication and transport does not, by itself, answer the question a data owner actually cares about: which specific agent is allowed to do which specific thing with this user’s account, and can the user see it and take it back. That is authorization at the level of the individual user and the individual agent, and it is the part builders keep having to solve themselves.

    The authorization gaps builders keep hitting

    Three problems show up again and again when agents get access through MCP.

    Static, over-broad credentials. An audit of more than 5,200 MCP servers found only 8.5% use OAuth. The majority rely on static API keys or personal access tokens, and most pass them through environment variables. A long-lived key in an env var is broad by default and rarely scoped to the one task at hand.

    The confused deputy. The MCP spec itself warns about it: when a server sits in the middle as an OAuth proxy and does not properly validate consent per client, an attacker can get access to a downstream API as the user without the user’s explicit approval. The spec’s own guidance is that proxy servers must implement per-client consent. The trouble is that this is left to each implementation to get right.

    Injected instructions turning access into exfiltration. Agents read untrusted content, and that content can carry commands. Invariant Labs showed a “toxic agent flow” where a malicious public GitHub issue steered an assistant into exposing private repositories through access it already held. EchoLeak (CVE-2025-32711) showed a single crafted email making Microsoft 365 Copilot leak internal data with no click. In each case the credential was valid. What failed was scoping and control over how that credential could be used.

    How to close the gap: user-mediated authorization on top of MCP

    User-mediated authorization is a model where the account holder grants the agent access directly, and the resulting credential is delivered to the user rather than pushed to the agent through an automated channel. The user hands it to their agent. There is no redirect, no callback, and no automated path between your app and the agent for a prompt injection or a misconfiguration to intercept.

    In practice that means:

    1. The user approves specific scopes in your app’s own UI, in plain language, in their authenticated session.
    2. The credential goes to the user, not the agent. The authorization decision happens outside the agent’s execution context, so an injected instruction has nothing to hijack.
    3. Access is scoped, time-limited, and revocable per agent. The user can pull one agent’s connection without breaking the others.
    4. Every call is checked against the grant, and each grant is recorded, so you can answer who authorized this agent and for what.

    This does not replace MCP. It sits on top of it. MCP tells the agent what it can do. User-mediated authorization decides whether it is allowed, on every call, under the user’s control.

    How it fits with the MCP spec

    MCP’s tightening authorization rules and user-mediated authorization are complementary. The spec’s hardening makes the OAuth plumbing safer between clients and servers. User-mediated authorization adds the piece the plumbing does not cover: end-user, per-agent, scoped consent that the user owns and can revoke. For an MCP server, the addition is small. Carry a user-approved token and verify it, per call, against the scopes the user granted. The agent gets a token it can use immediately, and the user keeps a dashboard of exactly which agents can do what.

    Frequently asked questions

    Does MCP handle authorization on its own?

    MCP provides an OAuth-based authorization framework and is hardening it, which covers authentication and the client-to-server flow. It does not, by itself, give end users per-agent, scoped, revocable control over what a specific agent can do with their account. That user-level authorization is the layer you add on top.

    Is an MCP server secure by default?

    No. Security depends on how it is implemented. Audits show most MCP servers rely on static API keys rather than OAuth, and the MCP spec itself warns that proxy servers must implement per-client consent to avoid confused-deputy attacks. A safe deployment scopes access to specific actions, delivers the credential to the user, and checks every call against what the user approved.

    What is a confused deputy attack in MCP?

    It happens when a server in the middle holds a user’s authorization and passes it downstream without properly checking, per client, that this particular agent was approved for it. The attacker never steals the credential directly; they get the intermediary to use its authority on their behalf. Per-client consent and validating authorization on every call are the defenses.

    Does adding user-mediated authorization slow the agent down?

    Approval happens once per grant, when the user allows it. After that the agent operates within its scope without re-prompting, and a self-describing token lets it start working without extra setup. The user gets control and an audit trail without turning every action into a permission dialog.

    AgentAdmit is the authorization layer for the agent economy: user-mediated, scoped authorization for AI agents that complements MCP. The credential is delivered to the user, not an automated channel. Scoped. Revocable. Auditable. See how AgentAdmit works.

    Related reading: What is user-mediated authorization for AI agents? and how to let an AI agent access a user’s account safely.

  • What Is User-Mediated Authorization for AI Agents?

    Short answer: User-mediated authorization is a model where the account holder grants an AI agent access directly, and the resulting credential is delivered to the user rather than pushed to the agent through an automated channel. The user gives the credential to their agent, so there is no redirect, callback, or automated path between the app and the agent for an attacker to intercept. Access is scoped to specific actions, time-limited, and revocable. It is how you answer the question every platform now faces as agents multiply: under whose authority is this agent acting?

    Why AI agents need a different authorization model

    Traditional access was built for two things: a person logging in, or one server calling another with a shared key. An AI agent is neither. It acts on a user’s behalf, often continuously, often across several services at once, and it decides in the moment which calls to make. That breaks the old assumptions in two ways:

    • The credential travels an automated channel. Most agent auth today leans on API keys, OAuth redirects, or environment variables. These move a credential with no human at the point of delivery, so they can be intercepted through prompt injection or misconfiguration.
    • The access is broad and hard to undo. Agents are often handed long-lived tokens that grant far more than the task needs, with no clean way to scope a single agent, expire its access, or revoke it on its own.

    The industry has started naming what goes wrong. Security teams call the accountability problem the attribution gap: the distance between what an agent did and your ability to prove who authorized it. When a credential rides an automated channel and grants broad access, an injected instruction can turn the agent into the attacker, and afterward no one can cleanly say who approved what. A model built for AI agents has to close both halves: the interception risk and the attribution gap.

    How user-mediated authorization works

    Four things keep the human in control at the moment access is granted.

    • The user grants access directly. Approval happens with the account holder, in plain language, for specific scopes. The developer does not stand in the middle holding the keys.
    • The credential is delivered to the user. It goes to the human, who gives it to their agent. There is no redirect, no callback, and no automated path between the app and the agent. This is the piece most systems skip, and it is what keeps the user as the authority.
    • The token is self-describing. The agent extracts where to exchange it from the token itself, and after exchange it receives its scopes, endpoints, and request schemas, so it can start operating without extra configuration or shared secrets.
    • Access is scoped, time-limited, and revocable. The user chooses what each agent can do and for how long, and can revoke one agent’s connection at any time without affecting others.

    How is this different from API keys or a normal consent screen?

    An API key or service account is a single broad secret that moves through an automated channel. It cannot express who approved it, it usually grants far more than one task needs, and revoking it tends to break everything else that shares it. A standard consent screen is better, but on its own it still typically returns the credential through an automated redirect or callback and hands the agent broad access.

    User-mediated authorization changes two things. The credential is delivered to the user instead of flowing to the agent automatically, and access is scoped per agent, time-limited, and revocable. The result is least-privilege access that is provable after the fact, not a broad secret you hope never leaks.

    Why deliver the credential to the user instead of the developer?

    Because that is what keeps the user as the authority. If the developer holds the credential, the user is trusting the developer’s infrastructure with their account. Delivering it to the user means a developer never has to custody raw credentials, and a breach of the developer’s systems does not expose user accounts.

    For a step-by-step version aimed at builders, see how to let an AI agent access a user’s account safely.

    Frequently asked questions

    Is user-mediated authorization the same as a standard login or authorization flow?

    No. It complements standards like OAuth rather than replacing them. It changes how the credential reaches the agent, through the user instead of an automated redirect or callback, and adds per-agent scoping, expiry, and revocation, so the human approves and controls access at the moment it is granted.

    Why not just push the credential straight to the agent?

    Because an automated path between your app and the agent is exactly what a prompt injection or a misconfiguration can intercept. Delivering the credential to the user removes that channel. The user gives it to their agent, so there is no automated hop for an attacker to sit on.

    Does this slow the agent down?

    Authorization happens once per grant, when the user approves it. After that the agent operates within the scope it was given without re-prompting, and a self-describing token means it does not need extra setup to start working. The user gets control and an audit trail without turning every action into a permission dialog.

    What is the simplest first step toward this model?

    Stop moving raw, broad credentials to agents through automated channels. Deliver scoped access that the user approves, make each connection time-limited and revocable on its own, and keep a record of every grant.

    AgentAdmit is the authorization layer for the agent economy: user-mediated, scoped authorization for AI agents. The credential is delivered to the user, not an automated channel. Scoped. Revocable. Auditable. See how AgentAdmit works.

  • How to Let an AI Agent Access a User’s Account Safely

    Short answer: To let an AI agent access a user’s account safely, keep the credential off any automated channel between your app and the agent. Most agent access today runs on API keys, OAuth redirects and callbacks, or environment variables, and those channels can be intercepted through prompt injection or misconfiguration. The safer path is user-mediated delivery: the credential is delivered to the human, and the human gives it to their agent. Pair that with access that is scoped to specific actions, time-limited, and revocable, and the user stays in control of exactly what their agent can do, with a record of who approved what.

    Why an AI agent changes the security picture

    A normal login authenticates a person who is present and reacting to what they see. An AI agent is different. It acts on the user’s behalf, often continuously, often across several services at once, and it decides in the moment which calls to make. It also reads untrusted content along the way, and that content can carry instructions.

    This is not hypothetical. In 2025, researchers showed that a single crafted email could make Microsoft 365 Copilot pull internal data and leak it to an outside server with no click from the user, a zero-click flaw tracked as CVE-2025-32711 and nicknamed EchoLeak. Around the same time, Invariant Labs demonstrated a “toxic agent flow” on the GitHub MCP server: a malicious public issue steered an assistant into exposing private repositories, using the same access the user had already granted it. In both cases the agent had a valid credential. The problem was what that credential could reach and how it was handled.

    Handing that kind of actor a broad, long-lived credential through an automated channel creates three problems:

    • The channel can be intercepted. API keys, redirects, and environment variables move a credential with no human at the point of delivery, so a prompt injection or a misconfiguration can quietly capture it.
    • The access is broader than the task. A single shared key usually grants far more than the one thing the agent was asked to do, so a leak exposes the whole account.
    • No one can prove or undo consent. If access was arranged through automated plumbing, there is no clean record that the user approved it, and no easy way to revoke one agent without breaking the rest.

    The default today leans into all three. An audit of more than 5,200 MCP servers found only 8.5% use OAuth. The majority rely on static API keys or personal access tokens, and most pass them through environment variables. Long-lived, broad, and sitting on an automated channel is exactly the combination these attacks feed on.

    What user-mediated delivery means

    User-mediated delivery puts the human back in the loop at the moment access is granted. Instead of the credential flowing straight from your app to the agent, it is delivered to the user. The user then gives it to their agent. There is no redirect, no callback, and no automated path between your app and the agent. The developer never has to hold the user’s raw credentials, and the user can see and control exactly what they are handing over.

    The reason this matters is where the authorization decision happens. It happens outside the agent’s execution context, in the user’s own authenticated session. So an instruction injected into the agent has nothing to hijack. There is no programmatic path from “injected prompt” to “new grant of access.”

    A safe-access checklist

    1. Keep credentials off automated app-to-agent channels. Don’t push an API key, a redirect, or an environment variable straight to the agent.
    2. Deliver the credential to the user. Route it back through the account holder, who passes it to their agent.
    3. Scope it to specific actions. Grant the minimum the task needs, in plain language the user approves.
    4. Time-limit it and make it revocable. Let the user set how long access lasts and revoke a single agent’s connection at any time, without affecting others.
    5. Use a self-describing token. A good token tells the agent where to exchange it and, after exchange, hands back its scopes, endpoints, and request schemas, so the agent can operate without extra configuration or shared secrets.
    6. Keep an audit trail. Record who approved which scope and when, and show it to the user.

    What this looks like in practice

    When access is delivered this way, it is least-privilege by default. An agent authorized to read one thing cannot quietly reach everything else. A single leaked token is limited to one scope on one account and can be revoked on its own. And because the user granted access directly and it was recorded, both the user and the platform can answer the question that matters as agents multiply: who authorized this, and for what.

    For the model behind this and why the credential goes to the user in the first place, see What is user-mediated authorization for AI agents?

    Frequently asked questions

    Can I just give an AI agent an API key?

    You can, but it is the least safe option. An API key is usually broad, moves through an automated channel that can be intercepted, cannot express who approved it, and is hard to revoke without breaking everything else that uses it. Scoped, user-delivered credentials limit the damage if the agent or its host is compromised.

    Does user-mediated delivery replace OAuth or a normal login?

    No. It complements standards like OAuth. It changes how the resulting credential reaches the agent, through the user rather than an automated redirect or callback, and adds per-agent scoping and revocation, so the human stays in control at the moment of access.

    Does the agent still end up with a credential?

    Yes, and that is fine. The difference is the path. The credential is delivered to the user, and the user gives it to their agent, so there is no automated channel between your app and the agent for an attacker to intercept.

    What is the simplest first step to make agent access safer today?

    Stop pushing raw, broad credentials to agents through automated channels. Move to scoped access that the user approves and delivers, keep a record of each grant, and make each connection revocable on its own.

    AgentAdmit is the authorization layer for the agent economy: user-mediated, scoped authorization that lets AI agents access user accounts with the credential delivered to the user, not an automated channel. Scoped. Revocable. Auditable. See how AgentAdmit works.