# MCP security risks and how to reduce them

> The MCP security risks a company faces, from prompt injection to keys in local configs, with an example and a fix for each, and who owns the fix.

**TL;DR** MCP security risks for a company come from three places: the content a model reads, the servers that hand it tools, and the credentials behind them. Elaichi reduces the server and credential risks with per-person OAuth, first-party connectors, per-tool restrictions, frozen arguments, credentials held outside the client and one audit log. Prompt injection happens inside the model's context, so it stays a client and model problem that Elaichi narrows but does not solve.

An engineer pastes a personal CRM token into a local MCP config. A support lead installs a community server from a registry. Neither asked security, and both agents now act inside company systems.

MCP (Model Context Protocol) is the standard way an AI assistant calls tools in other apps. MCP security risks come from three places: the content the model reads, the servers that hand it tools, and the credentials behind those servers. Each risk here has a source, an example, a fix and an owner.

## What are the MCP security risks for companies, and how do you reduce them?

Nine risks recur across the MCP specification and OWASP's lists. Most are reduced by where credentials live and how narrow each grant is. Prompt injection is not, because it happens inside the model.

The sources are the MCP [Security Best Practices](https://modelcontextprotocol.io/specification/2026-07-28/basic/security_best_practices), the [OWASP MCP Top 10](https://owasp.org/www-project-mcp-top-10/) (a beta release) and the OWASP Top 10 for LLM applications.

| Risk | What reduces it | Who owns the fix |
|---|---|---|
| Prompt injection through tool results | Least privilege, approval for writes, a record of every call | The client and the model |
| Tool poisoning and rug pulls | Tools from one accountable author, rules bound to operations | Whoever authors the server |
| Token passthrough and confused deputy | Tokens issued only for the server, consent on every sign-in, exact redirects | The MCP server |
| Personal keys in local configs | Per-person OAuth, app credentials held on the server | IT, with a control plane |
| Over-broad scopes and shared accounts | Narrow consent, per-tool rules per role, frozen arguments | Admins, with a control plane |
| Unvetted community and local servers | First-party connectors, an inventory, client sandboxing | IT and endpoint security |
| Tool sprawl | Search instead of a long list, restrictions applied first | The control plane |
| Missing audit | One record per call, naming the person, client and account | The control plane |
| Access that outlives the person | Grant revocation on removal | IT, with a control plane |

## How does prompt injection reach an agent through tool results?

Through content the agent reads. A ticket, email or document can contain text written as an instruction, and the model may follow it. OWASP's [LLM01 Prompt Injection](https://genai.owasp.org/llmrisk/llm01-prompt-injection/) calls this indirect injection, and says it is unclear whether any method prevents it fully.

Example: a support ticket tells the assistant summarizing it to email the customer list to an outside address. If the agent holds a tool that can do that, the instruction has somewhere to go.

Elaichi does not stop this, because an MCP server never sees the user's prompt. The prompt-injection write gate lives in the Elaichi agent window and does not apply to a raw tool call.

OWASP lists least privilege and human approval for high-risk actions among its mitigations. In Elaichi, a restriction can withhold named write tools, or a whole connector, from a role, and every call leaves a record. Approval for writes belongs in the client, as [human approval for agent actions](/blog/human-approval-for-ai-agent-actions/) explains.

## What are tool poisoning and rug pulls?

Tool poisoning hides instructions in a tool's description, which the model reads in full and the person rarely sees. A rug pull is a server changing a description after you approved it.

[Invariant Labs described both in April 2025](https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks). Their test server offered a harmless-looking `add` tool to Cursor. Its description told the agent to read the user's MCP config file and SSH private key and pass them out. OWASP lists the same attack as MCP03, Tool Poisoning. Invariant recommends showing users full descriptions and pinning server versions by hash.

Elaichi authors, maintains and serves its connectors from its own infrastructure. Tool descriptions for the catalog therefore come from one accountable vendor, not from whoever published a server. A custom connector is written by the organization that creates it. Allow rules also bind the operation, not the label, because whoever edits a connector's documentation can rename a tool.

A custom connector forked from a public one takes upstream changes only through a review, where conflicts and destructive removals start unchecked. A description is still text the model reads, so an accountable author narrows who writes it, not how the model treats it.

## What are token passthrough and the confused deputy problem?

Token passthrough is a server forwarding a client's token to a downstream API without checking it was issued for itself. The MCP specification forbids it: a server must not accept tokens that were not issued for it.

In the confused deputy attack, a proxy holds one OAuth app (OAuth is the standard for delegated sign-in) at a third party, lets clients register themselves, and the third party remembers consent in a cookie. An attacker registers a client with their own redirect address and sends the user a link. Consent is skipped, and the code lands with the attacker. The specification's fix is per-client consent naming the client, its scopes and its redirect address, plus exact redirect matching.

In Elaichi, the client holds an Elaichi grant, never the app's credential, and each authorization request lands on a consent screen that names the app, requires PKCE and matches the redirect address exactly. [The review checklist](/blog/mcp-security-review-checklist/) lists what a consent screen should show.

## Why are personal API keys in local MCP configs a risk?

A key in a file is a long-lived secret that anyone with the file can use, and it does not end when its owner leaves. OWASP's MCP01, Token Mismanagement and Secret Exposure, names hard-coded secrets in config files, long-lived tokens and shared service accounts.

Invariant Labs' tool-poisoning test targeted exactly that file, so a key stored there can leave with it.

Elaichi puts no secret in the config. The address, `https://api.elaichi.ai/mcp`, is the same for every organization and carries no token. Each person signs in with OAuth.

Elaichi stores only a keyed hash of each token, and app credentials live in a separate credential service, encrypted at rest with AES-256-GCM ([the checklist](/blog/mcp-security-review-checklist/) has the detail). As a backstop, tool results pass through a scrubber that replaces values under secret-named keys, such as `api_key` or `password`, with `[redacted]`. [OAuth versus long-lived keys](/blog/oauth-vs-api-keys-for-ai-agents/) compares the two, and [replacing personal MCP servers](/blog/replace-personal-mcp-servers/) covers finding them on laptops.

## Where do over-broad scopes and shared accounts go wrong?

A broad token turns one leak into access to everything it covers, and a shared account hides who acted. The MCP specification's scope minimization section warns that a stolen broad token enables lateral access. It recommends starting small and asking for more when needed. OWASP's MCP02 calls the slow version privilege escalation via scope creep.

The common failure is one admin-scoped service account in the CRM, used by five people's agents. The CRM's log then shows one name for every change.

On Elaichi's consent screen, delete is never pre-ticked and a client that requests no scope gets read only. [The checklist's consent questions](/blog/mcp-security-review-checklist/) show what to ask any vendor.

The trade-off: a shared connection runs on its owner's credential, so calls through it reach the app as that account. Sharing one connection with the whole organization rebuilds the shared account. Where the app's own permissions matter, have each person connect their own account.

## How do you enforce least privilege for AI agents across SaaS apps?

Run each call as the person who made it, then narrow it by role and by tool on the server, not in the prompt. OWASP's [LLM06 Excessive Agency](https://genai.owasp.org/llmrisk/llm062025-excessive-agency/) traces agent damage to excess functionality, permissions and autonomy. It recommends acting in the user's own context, with authorization enforced downstream rather than by the model.

Each Elaichi member holds exactly one role, and restrictions decide which connectors and which individual tools a target may reach. Rules are enforced at execution, and a change takes about two minutes. [Restricting one tool or the whole app](/blog/per-tool-vs-per-app-restrictions/) works through six cases.

Where a tool is right but one argument is dangerous, a frozen parameter locks it, such as the payee on a payment tool. One condition: a freeze binds only calls made through its toolbox entry, so share the toolbox with the people it governs, not the connection itself.

## Why are unvetted community MCP servers a supply chain risk?

Installing a server means running someone else's code with your client's privileges, or sending your data to someone else's host. The MCP specification's local server section describes malicious startup commands and data exfiltration. It requires clients to show the exact command and get consent first, and recommends sandboxing.

OWASP's MCP09, Shadow MCP Servers, sets a blunt test: if security cannot list every active server, unapproved ones already exist.

Elaichi leaves nothing to install. Connectors are authored and served by Elaichi, and the catalog runs to 500+. A control plane never sees a server someone installs on a laptop, though. That stays with endpoint controls and client policy. [First-party connectors against a registry](/blog/mcp-registry-vs-first-party-connectors/) covers the authorship trade-off.

## Does tool sprawl make an agent less safe?

Yes. Every tool an agent does not need is functionality OWASP's Excessive Agency entry tells you to remove. [Why long tool lists fill the context window](/blog/context-window-problem-mcp-tools/) has the detail.

Search also fails without a relevance floor, returning a tool from an app nobody asked about, which the model then calls. Elaichi's search requires a match to carry at least half the query's weight.

In Elaichi, connected tools are never listed one by one, however few there are. The model finds a tool with `search_tools` and runs it with `execute_tool`. Restrictions apply before search, so a withheld tool's name never goes on the wire.

## What happens when nobody can say what an agent did?

The incident review stalls, and nobody can prove access ended. OWASP's MCP08, Lack of Audit and Telemetry, warns that without logs there is no trace of agent actions.

Elaichi records one entry per tool-call attempt, succeeded or failed. Each entry names the person, the client that made the call, the account actually reached and the outcome. The trail logs argument names and counts, and never argument values. [The fields an agent audit log needs](/blog/what-an-ai-audit-log-must-capture/) lists the rest.

In Elaichi, removing or suspending a member revokes every live grant in the same transaction as the membership change, so the person's next call fails, and [a contractor's last day](/blog/offboarding-when-the-agent-holds-access/) walks through the rest of the order.

## Where do you start a vendor review?

Send every vendor the same written questions, then test the answers. Ask how people sign in, where credentials live, what consent pre-ticks and how fast access ends. Revoke a grant and confirm the next call fails. Then change a rule and time how long it takes.

The [ten-question MCP security review](/blog/mcp-security-review-checklist/) has each question and what a good answer looks like.

## When do you not need a control plane for these risks?

When nobody has connected an AI client to a company system yet. Copying and pasting into an assistant is a content problem, and DLP (data loss prevention) fits it better, as [what a CASB can see](/blog/casb-dlp-vs-governed-mcp-endpoint/) explains.

One team using one app may not need one either, because many apps ship their own MCP server under their own permissions. That holds until a second app or client arrives and you need one set of rules across them. [What an MCP control plane is](/blog/what-is-an-mcp-control-plane/) sets out that shape, and the [connector catalog](/connectors/) shows which apps it covers.

## FAQ

### What are the main MCP security risks for a company?

The recurring ones are prompt injection through content the agent reads, poisoned or silently changed tool descriptions, token passthrough and the confused deputy problem, personal API keys in local config files, over-broad scopes and shared accounts, unvetted community servers, tool sprawl, and missing audit records. Most are fixed on the server side by per-person sign-in, narrow grants and a record of every call. Prompt injection is the exception: it happens inside the model, so least privilege and human approval limit the damage rather than prevent it.

### What is MCP tool poisoning?

Tool poisoning hides instructions in an MCP tool's description. The model reads the full description and the person usually sees only the tool's name, so the hidden text can steer the agent, for example toward reading a local key file and sending it out. A rug pull is the same attack delivered later, when a server changes a description after it was approved. The defenses are tools from an accountable author, showing the full description, pinning server versions, and access rules that bind the operation rather than the tool's label.

### Is token passthrough allowed in MCP?

No. The MCP specification forbids it. An MCP server must not accept a token that was not issued for that server, and it must not forward a client's token to a downstream API. Passing tokens through breaks the audience boundary, lets a stolen token use the server as a proxy, and leaves the downstream log showing the wrong identity.

### How do you enforce least privilege for AI agents across SaaS apps?

Run each call as the person who made it, with their own OAuth grant, and decide on the server which tools each role may reach. In Elaichi, every member holds one role, restrictions name which connectors and which individual tools a role or user may reach, delete access is never pre-ticked on the consent screen, and a frozen parameter can lock one argument, such as a payee, so the model cannot change it. A role or restriction change takes about two minutes to apply.

### Does Elaichi protect against prompt injection?

No. An MCP server never sees the user's prompt, so it cannot judge whether an instruction came from the person or from content the model read. What Elaichi enforces limits what an injected instruction can reach: role-based permissions per operation, per-tool restrictions, OAuth scope limits with delete never pre-ticked, and an audit record for every call. Approval for writes belongs in the AI client.

## Read next

- [MCP security review checklist: ten questions](/blog/mcp-security-review-checklist/) — An MCP security review checklist: ten questions to ask before approving an MCP server or gateway, what a good answer looks like, and Elaichi's answers.
- [OAuth or API keys for AI agents?](/blog/oauth-vs-api-keys-for-ai-agents/) — Choosing OAuth or API keys for AI agents comes down to revocation: a grant is checked on every call, while a key works until someone rotates it.
- [What an AI agent audit log must capture](/blog/what-an-ai-audit-log-must-capture/) — An AI agent audit log must capture who acted, which client called, which account was reached, what was tried and how it ended. Argument values stay out.
