In this article
April 8, 2026
April 8, 2026

Securing agentic apps: How to vet the tools your AI agents depend on

30 CVEs in 60 days, a backdoored npm package stealing emails, and a hosting platform flaw that put 3,000 servers at risk. Here's how to secure the supply chain your AI agents depend on.

In September 2025, someone published an npm package called postmark-mcp. It looked like the real thing: correct naming convention, plausible README, working email functionality. It was a near-perfect replica of the official Postmark Labs MCP server. The attacker built trust over 15 versions of normal-looking updates before adding a single line of code in version 1.0.16 that BCC'd every outgoing email to an external address. Internal memos, password resets, invoices, customer communications. All quietly forwarded through a tool the developer installed in good faith.

This is ASI04 from the OWASP Top 10 for Agentic Applications: agentic supply chain vulnerabilities. Traditional supply chain attacks target your build pipeline. Agentic supply chain attacks target your runtime. When your agent dynamically loads tools from an MCP server, fetches prompt templates from a registry, or delegates to a third-party sub-agent, each of those components becomes a trust boundary you need to verify.

The MCP ecosystem has grown at a pace that has outrun its security infrastructure. The official MCP Registry launched in September 2025 and reached nearly 2,000 entries within months. Unofficial registries index over 16,000 servers. One analysis of company-operated MCP servers found the count more than tripled between August 2025 and February 2026, with the rate of new servers accelerating every month. Between January and February of 2026, security researchers filed roughly 30 CVEs against MCP servers, clients, and infrastructure. The root causes were not exotic zero-days. They were missing input validation, absent authentication, and blind trust in tool descriptions. The same classes of vulnerability that plagued npm and PyPI for years are now showing up in the infrastructure that gives your AI agents their capabilities.

If you read the first article in this series on giving your AI agents their own credentials, you've already handled the identity layer: who is acting, and what are they authorized to do. This article covers the layer beneath that: can you trust the tools they're calling in the first place?

The attack surface is your entire tool chain

In a traditional application, your supply chain is your dependency tree: packages, libraries, container images. You audit them at build time, pin versions, run vulnerability scanners, and ship. The dependency tree doesn't change at runtime.

In an agentic application, the supply chain extends into runtime. Your agent connects to MCP servers that expose tools. Those tools have descriptions that the LLM reads to decide when and how to call them. The servers might be first-party (you built them), third-party (someone else built them), or hosted on a platform you don't control. Any of these can change between the moment you approved them and the moment your agent calls them.

This creates four attack surfaces that don't exist in traditional software:

  • Tool description poisoning. The LLM reads tool descriptions to decide which tool to call and how to call it. A malicious or compromised MCP server can embed hidden instructions in those descriptions, causing the agent to call tools in unintended ways, exfiltrate data, or skip other tools entirely. Researchers demonstrated this against the WhatsApp MCP Server, where poisoned tool descriptions tricked agents into exfiltrating entire chat histories.
  • Runtime tool mutation. You approved an MCP server's tool definitions last week. This week, the server pushed an update that changed the behavior of one tool or added a new one. Most MCP clients operate on an approve-once-trust-forever model: once you've approved a server, changes to its tools are accepted silently. A legitimate server that gets compromised after your initial review is indistinguishable from the server you originally trusted.
  • Hosting platform compromise. When you use a hosted MCP server platform, you're trusting not just the server code but the infrastructure it runs on. In 2025, GitGuardian researchers discovered a path traversal vulnerability in Smithery.ai, a popular MCP hosting platform, that could have allowed an attacker to escape the container boundary and access credentials for over 3,000 hosted MCP servers. Smithery fixed the flaw within days of disclosure, and there was no indication it was exploited in the wild. But the incident demonstrated that a single bug in the hosting layer could potentially expose every server on the platform and every API key those servers held.
  • Transitive dependency chains. Your MCP server depends on npm packages. Those packages depend on other packages. The mcp-remote npm package, a widely used proxy for connecting local MCP clients to remote servers, had a critical vulnerability (CVE-2025-6514, CVSS 9.6) that allowed full remote code execution when connecting to an untrusted server. The flaw was in the OAuth authorization flow: a malicious server could respond with a crafted authorization endpoint URL that triggered OS command injection. Over 400,000 installations were affected.

Why traditional supply chain defenses are not enough

If you're used to securing npm or PyPI dependencies, your instincts are partially right but incomplete. The standard playbook (pin versions, run Dependabot, check advisories) covers the package dependency layer. But MCP introduces attack vectors that sit above the package layer.

  • Tool descriptions are executable in practice. In a traditional dependency, the interface is defined by code: function signatures, type definitions, API contracts. In MCP, the interface includes natural language descriptions that the LLM interprets. This means a tool's behavior can be altered by changing its description, without changing any code. Your vulnerability scanner won't flag a description change because it's not a code change. But to the LLM, a description change is functionally equivalent to changing the tool's behavior.
  • The approve-once model has no analog in traditional package management. When you pin a package version, you get that exact version every time. When you approve an MCP server, you're approving a live endpoint that can change at any time. There's no lockfile equivalent for MCP tool definitions. The tool schema you validated during setup might not be the schema the server returns next Tuesday.
  • MCP servers run with high trust by default. A typical npm package runs in your application's process with the same permissions as your code. An MCP server runs as a separate service with its own credentials, often configured with API keys that grant access to production systems: databases, email services, cloud infrastructure. A compromised npm package can do damage within your application. A compromised MCP server can do damage across every system it connects to.

Securing your agent's supply chain

The fix is layered, just like traditional supply chain security. No single control is sufficient, but the combination creates meaningful defense in depth.

Verify server identity before connecting

Treat every MCP server as untrusted infrastructure until it authenticates. This sounds obvious, but as of early 2026, security researchers found that a large fraction of MCP servers accept unauthenticated connections. The Azure MCP Server itself shipped without authentication, resulting in a CVSS 9.1 vulnerability (CVE-2026-32211) disclosed in April 2026.

Your MCP client should require OAuth 2.1 authentication for every remote server connection. The server presents its identity, the client validates it, and all subsequent communication happens over authenticated channels. If a server can't authenticate, your agent doesn't connect.

This is where the identity infrastructure from the previous article pays off. WorkOS AuthKit handles the OAuth 2.1 flows for MCP server authentication, including the PKCE flow for user-authorized connections and client credentials for machine-to-machine communication. The same infrastructure that gives your agents their own credentials also verifies the identity of the servers they connect to.

Pin and validate tool definitions

Don't trust tool descriptions at face value. When you first connect to an MCP server, capture the complete tool manifest: every tool name, description, parameter schema, and return type. Store this as your known-good baseline. On every subsequent connection, compare the server's current manifest against your baseline.

If a tool's description changes, that's a signal that needs investigation, not silent acceptance. If a new tool appears that wasn't in the original manifest, your agent should refuse to use it until a human reviews and approves the addition.

  
interface ToolManifest {
  serverUrl: string;
  serverVersion: string;
  capturedAt: string;
  tools: {
    name: string;
    description: string;
    parameterSchema: Record<string, any>;
  }[];
  hash: string;  // SHA-256 of the serialized manifest
}

async function validateToolManifest(
  server: MCPServer,
  knownGood: ToolManifest
): Promise<{ valid: boolean; changes: string[] }> {
  const current = await server.getToolManifest();
  const changes: string[] = [];

  // Check for modified tools
  for (const tool of current.tools) {
    const baseline = knownGood.tools.find(t => t.name === tool.name);
    if (!baseline) {
      changes.push(`New tool added: ${tool.name}`);
      continue;
    }
    if (tool.description !== baseline.description) {
      changes.push(`Description changed: ${tool.name}`);
    }
    if (JSON.stringify(tool.parameterSchema) !== JSON.stringify(baseline.parameterSchema)) {
      changes.push(`Schema changed: ${tool.name}`);
    }
  }

  // Check for removed tools
  for (const tool of knownGood.tools) {
    if (!current.tools.find(t => t.name === tool.name)) {
      changes.push(`Tool removed: ${tool.name}`);
    }
  }

  return {
    valid: changes.length === 0,
    changes,
  };
}
  

If the manifest doesn't match, halt. Don't fall back to using the server anyway. A manifest change is either a legitimate update (which should go through your approval process) or an indicator of compromise (which should trigger an investigation).

Validate tool arguments at the boundary

Even with a trusted MCP server, validate what your agent sends to it. The agent's tool calls should be checked against the schema before they leave your system, not just validated by the server.

  
const argumentPolicies: Record<string, (args: any) => boolean> = {
  'send_email': (args) => {
    // Only allow emails to approved domains
    const allowedDomains = ['yourcompany.com', 'partner.com'];
    const domain = args.to.split('@')[1];
    return allowedDomains.includes(domain);
  },
  'query_database': (args) => {
    // Block write operations
    const query = args.sql.trim().toUpperCase();
    return query.startsWith('SELECT') && !query.includes('INTO');
  },
  'write_file': (args) => {
    // Restrict to allowed paths
    return args.path.startsWith('/tmp/agent-workspace/');
  },
};

function validateToolArguments(toolName: string, args: any): boolean {
  const policy = argumentPolicies[toolName];
  if (!policy) {
    // Default deny: unknown tools are blocked
    return false;
  }
  return policy(args);
}
  

This catches the class of attacks where a poisoned tool description causes the agent to call a legitimate tool with malicious arguments. The tool itself is fine. The schema is correct. But the arguments the agent chose (influenced by a manipulated description from another tool) would do damage if executed.

Sandbox third-party servers

Run third-party MCP servers in isolated environments with restricted network access. The server should be able to reach only the specific external services it needs and nothing else. If a filesystem MCP server is compromised, it shouldn't be able to make outbound HTTP requests to exfiltrate data. If a database MCP server is compromised, it shouldn't be able to reach your email infrastructure.

The container isolation should include:

  • Network restrictions: whitelist the specific endpoints the server needs. Block all other outbound traffic.
  • Filesystem restrictions: mount only the directories the server needs, read-only where possible.
  • Resource limits: cap CPU, memory, and process count to prevent denial-of-service from a misbehaving server.
  • No credential inheritance: the server gets only its own scoped credentials, never the host's environment variables or mounted secrets.

This is standard container security practice, but it's frequently skipped for MCP servers because they're treated as development tools rather than production infrastructure. Once your agent is using them in production workflows, they need production-grade isolation.

Audit your dependency tree

Your MCP server's npm or pip dependencies are part of your supply chain. Apply the same controls you'd apply to any production service:

  • Pin exact versions. Use npx -y @modelcontextprotocol/server-filesystem@2025.11.18, not npx -y @modelcontextprotocol/server-filesystem. The standard MCP installation method (npx -y package-name) fetches the latest version from npm with zero verification. One compromised publish and every new installation is backdoored.
  • Verify publisher identity. The official MCP reference servers are published under the @modelcontextprotocol/ scope. Not @anthropic-ai/, not @mcp/, not unprefixed names. Check download counts, publish dates, and publisher history. A "Postmark MCP server" published last week with 12 downloads is suspicious.
  • Run security scanners. mcp-scan and similar tools can audit your MCP configuration for known vulnerabilities. Run them in CI, not just manually. The scan should cover both the MCP server packages and their transitive dependencies.
  • Monitor for updates. When a dependency publishes a new version, review the changelog before updating. After updating any MCP server, re-read the tool manifest and re-approve it in your client.

Scan tool descriptions for hidden instructions

Tool description poisoning is the supply chain equivalent of prompt injection. A malicious tool description might include hidden text that instructs the LLM to behave differently: ignore other tools, exfiltrate data to a specific endpoint, or override the user's instructions.

Before your agent loads any tool description, scan it for patterns that look like instructions rather than descriptions:

  
const suspiciousPatterns = [
  /ignore\s+(previous|other|all)\s+(instructions|tools)/i,
  /do\s+not\s+(mention|reveal|show|tell)/i,
  /instead\s+of\s+(calling|using|invoking)/i,
  /send\s+(data|results|output)\s+to/i,
  /\bsecretly\b/i,
  /\bhidden\b.*\binstructions?\b/i,
  /override\b/i,
];

function scanToolDescription(description: string): {
  safe: boolean;
  flags: string[];
} {
  const flags: string[] = [];
  for (const pattern of suspiciousPatterns) {
    if (pattern.test(description)) {
      flags.push(`Suspicious pattern: ${pattern.source}`);
    }
  }
  return {
    safe: flags.length === 0,
    flags,
  };
}
  

This is not a complete defense. Sophisticated attackers can craft descriptions that evade simple pattern matching. But it catches the low-hanging fruit, and combined with manifest pinning and argument validation, it adds another layer to the defense.

The hosting platform question

The Smithery incident highlights a specific architectural decision that many teams haven't thought through: where do your MCP servers run?

Self-hosted servers give you full control over the infrastructure, dependencies, and network configuration. You're responsible for patching, monitoring, and isolation, but you're not trusting a third party with your credentials or your agent's tool definitions.

Hosted platforms simplify deployment but create a single point of failure. A vulnerability in the platform affects every server on it. The Smithery path traversal exposed credentials across 3,000 servers, not because any individual server was flawed, but because the hosting infrastructure had a bug.

Hybrid approaches where you host your own critical MCP servers (the ones with access to production data, customer information, and financial systems) and use hosted platforms for less sensitive tools (documentation search, general-purpose utilities) give you a reasonable trade-off.

For any server that handles sensitive data, the security posture of the hosting infrastructure matters as much as the security of the server code itself. Ask: who has access to the credentials my server uses? What isolation exists between my server and other tenants? What happens if the platform itself is compromised?

Building a review process

Supply chain security is not a one-time audit. It's an ongoing process. Here's what a practical review cadence looks like for MCP servers:

  • Before connecting a new server: Verify the publisher. Read the source code if it's open source. Capture the tool manifest as your baseline. Run mcp-scan or equivalent. Sandbox the server. Configure argument validation policies for each tool. Test the server with known-safe inputs before exposing it to your agent.
  • Weekly: Re-validate tool manifests against your baseline. Check for new CVEs against your MCP server dependencies. Review audit logs for unusual tool invocation patterns (sudden spikes in calls to a specific tool, new argument patterns, failed authorization checks).
  • On any server update: Diff the new tool manifest against the baseline. Review the changelog. Re-run security scans. Re-approve the manifest if the changes are legitimate. Investigate if changes are unexpected.
  • On any incident: Check whether the compromised component touched any MCP servers. Review whether tool descriptions changed around the time of the incident. Audit the full delegation chain from user authorization through agent identity to tool invocation.

What comes next

Supply chain security tells you whether to trust the tools your agents connect to. The next article in this series covers what happens when the tools are legitimate but the agent uses them in dangerous ways: tool misuse and policy enforcement at the invocation layer. That's where argument validation, tool chain analysis, and runtime policy controls come together with the identity and supply chain layers we've already built.

The OWASP Top 10 for Agentic Applications describes ten risks, but the defenses are cumulative. Identity scoping (who can act), supply chain verification (which tools can they call), and invocation policy (how can they call them) form three layers that work together. Skip any one of them and the other two can't compensate.

If you're looking to secure the identity and authentication layer for your MCP servers, WorkOS provides OAuth 2.1 authentication, tool-level authorization with RBAC and FGA, and audit logging out of the box, including native support for MCP server authentication.

This site uses cookies to improve your experience. Please accept the use of cookies on this site. You can review our cookie policy here and our privacy policy here. If you choose to refuse, functionality of this site will be limited.