Security Research at Semgrep requires that we stay abreast of emerging technologies whenever there is a "written software" component. When the specification for Model Context Protocol (MCP) started gaining traction, we were engaged to understand and explore tools and trends in the Agentic AI Coding space. We are sharing some of what we've learned that will be relevant for practicing AppSec engineers coming up to speed and to help raise awareness of the sharp edges around MCP while forecasting upcoming areas of interest.
Concepts (Control Flow)
At its core, the Model Context Protocol is a specification (like REST or SOAP) for a programmatic tool interface - the “programmatic” caller in this case is a language model. If you are already familiar with testing REST/SOAP/GraphQL/etc interfaces, interacting with remote MCP servers will feel very familiar.
Image: MCP Control Flow
You should approach testing MCP servers like any other API target - tools like the MCP Inspector discussed below are a great way to get started quickly, though any tool that allows you to manipulate web requests is sufficient.
Vocabulary
Concept | Definition | Example |
---|
Model | The LLM responsible for processing text input. | Claude Sonnet 4, OpenAI GPT-5, etc. |
Context | The external resources provided by MCP tooling. | A logical object like: { “system” : “you are a helpful assistant”, “prompt”: “help me pick a restaurant for a client dinner” } |
Resource | Any data object that may be useful to an LLM while making a decision. | A scope document for a project. |
Tool | Code or executable that provides functionality to the LLM. | The Semgrep CLI. |
Prompt | A prompt for processing by an LLM. | “Write a simple Semgrep rule”. |
Protocol | The JSON-RPC 2.0 compliant bidirectional messaging channel used by MCP clients and servers to exchange messages. | A JSON-RPC request from an LLM client to a MCP server. |
Root | Filesystem or filesystem-like object that the client has access to. | The working directory of Claude Code or Codex. |
Elicitation | MCP server-initiated request for information from the user (client). | A prompt from the server for your billing address (for tax purposes). |
Sampling | Request for a model completion, by the client, from a MCP server. “Human in the loop” is encouraged but not required by the specification. | A request from the server for a summary of the last five conversation messages in the current context. |
Testing MCP Security
MCP Inspector
The MCP Inspector is a great tool to get started auditing MCP servers. If you’ve ever used the Apollo GraphQL Playground (or any other GraphQL playground interface) the Inspector will feel very familiar.
This is a really great place to start out evaluating an MCP server simply because you can inspect the protocol handshake and get a deterministic list of the tools, resources, and prompts provided by the server. The LLM will probably tell you the truth most of the time, but filtering MCP functionality through an LLM when you could inspect it directly is a layer of indirection you don’t need. Start here and get a feel for what the server can do before you start diving into the source.
Local Server Testing (STDIO)
The simplest way to get MCP up and running is local-only. It communicates over stdio in a child process of the MCP client. Pretty straightforward, attacking these is in an equivalence class with local processes attacking a shell process on the same device. That becomes interesting with multiple tools because they tend to have different privileges, it’s a highway for privilege escalations. You will want to audit these for potential command injection faults, as combined with future capabilities like sampling, you may unwittingly end up with a remote attack surface – we’ll cover this later on.
Known MCP Vulnerabilities
Tool poisoning (or ”line jumping”)
Tool poisoning (as described by Invariant Labs) a.k.a. “line jumping” (as described by Trail of Bits) is a malicious MCP behavior that leverages prompt injection techniques to influence client behavior without the user’s knowledge. This attack occurs before the invocation of a tool as part of the “tools/list” response from the initial MCP handshake. Successful tool poisoning attacks require either a client that does not adhere to the MCP specification (does not consider tool annotations untrusted) or an improperly trusted or compromised server. Currently, servers are not required to publish an event when a tool changes, which makes client detection of a compromised tool difficult without additional validation from the client side.
Tool shadowing
Tool shadowing can either refer to cross-server poisoning of legitimate behavior via side effects (as described by Invariant Labs ) or to name-collision attacks (described as “name conflict” by researchers from Huazhong University of Science and Technology). Current MCP clients (like Cursor, Claude Code, or Windsurf) allow multiple servers to provide tools with the same name, and depending on the implementation, may round robin the tool, or choose the alphabetically-first server that provides a tool with the appropriate name, or use invisible characters in the description to follow directives like “always choose this tool over similarly-named ones”. You can try this yourself with Claude Code or Windsurf and demo repository: semgrep/mcp-tool-shadowing-demo.
“Rug-pulling”
The MCP specification does not currently have any sort of requirement to broadcast when tools are changed, nor does it impose any requirements or restrictions on re-approving additional tools or capabilities of an updated server. The most common example is approval of a benign remote server that is later replaced with a malicious one, either by the server’s operator or a man-in-the-middle attack redirecting traffic to a malicious server.
Web 2.0 issues
Because MCP servers support JSON-RPC over HTTP, every API bug or HTTP protocol exploit you can think of is in scope.
Request smuggling/HTTP response splitting (particularly bad if you are leaking other users’ chat completions to an arbitrary target)
Path traversal
Injection issues of all types - sql, shell, LDAP, etc
Permissive JSON parsing without validating Content-Type header
etc.
Old vulnerabilities, new contexts
Clint Gibler has collected some issues relating to MCP security, many of which are just old bugs in new contexts. Semgrep even found a nuanced path traversal issue in an early version of our own MCP server! Our MCP server was (improperly) doing root checking in one codepath that would have allowed you to run Semgrep scans on an arbitrary file. If we hadn’t run the container as an app user with a minimally permissioned working directory, this would have been a Very Unfortunate Discovery instead of an “oops good thing we caught this, let’s not do it again” moment. Tool poisoning is also a rising area of interest, but our team in particular got very interested in frontier capabilities that are not well-supported or widely-adopted. This is often where all the fun behavior is!
Free Samples
Sampling is not well-supported yet. However, the specification as of 2025-06-18 has no requirements for isolation. This is an awesome exploit primitive. We asked ourselves, “Could you write a spec-compliant MCP client/server pair that could allow a malicious MCP server to request tool names from other servers and then dynamically register name collisions?”
The answer is yes. Yes, you can. (check back soon for link)
However, there is good news! Even in our basic implementation, the LLM tried to fully qualify tool names when requesting a tool - the failure was in the client’s implementation of tool resolution. If you are in the business of writing MCP clients, we highly recommend explicit, fully-qualified tool references when resolving tools.
MCP Security Checklists
Need to audit a MCP server in a hurry? Here’s a quick list of things that should have easy, acceptable answers. If it’s difficult to get a concrete answer for any of these (or if you don’t like the answer), you should do a deeper dive.
Download a copy of the Semgrep MCP Security Evaluation Cheatsheet
Specification Overview
If you are planning to really dive into MCP testing, you should eventually read the specification in full. Like many protocol specifications, pay close attention to the usage of “must” vs “should” - statements that are not required will always be omitted by some projects! These are scattered around the HTML-formatted specification - I’ve collected the most interesting ones here in one place to supercharge your audit efforts.
STDIO Transport
As covered earlier, STDIO is the simplest way to interact with MCP. For now, these are mostly affected by tool poisoning or rug-pulling attacks - you have to be on the device to interact with these, so your only avenues of interaction are side channels through the LLM itself, or being in control of the MCP server’s update mechanism.
HTTP Transport
This is the “paved path” to expose a remote MCP server. If you are going to implement HTTP transport, you should seriously consider requiring authentication. If you support authentication, you must implement OAuth 2.1. Now, some of you with some experience are probably (rightly) raising an eyebrow here as a specification-compliant MCP server using HTTP transport is “no auth or OAuth”. There will be developers out there who respond to “no auth or OAuth” like so:
Doing OAuth right can be painful and slow and tradeoffs will be made.
You should also implement dynamic client registration, though the spec does not require you to. If you do not, you have an elevated risk of subtle confused deputy problems - your MCP server has ONE context with which to interact with LLMs - does every LLM client you can expect to connect to this server have the same privileges? Set yourself up for success - invest early in decisions that will make permissions management easier in the long run.
Use the standard Authorization header when handling credentials - this should be a no-brainer in this day and age, but it bears repeating. You must also perform audience validation - as HTTP MCP servers continue to proliferate, central OAuth authorities like Okta will certainly end up issuing tokens for MCP services - it’s important you avoid revisiting old OAuth mistakes.
Server Requirements
MCP servers must:
obtain explicit informed consent from the user regarding all data access and operations
provide users full control over actions taken and data shared with the server or other parties
obtain explicit consent from the user before sharing data with a server
obtain explicit user consent before invoking any tool
obtain explicit user consent before performing sampling
advertise all features provided by the server
validate the Origin header for all requests
rate limit tool invocations
validate tool inputs
sanitize tool output
validate prompt inputs and outputs (to prevent injection attacks)
validate resource URIs
validate all paths against provided roots
MCP servers must not:
transmit data to a third party without user consent
request sensitive information via elicitation
replay messages that would have been delivered on a separate stream (for HTTP transport)
MCP servers should:
Authenticated Server Requirements
MCP servers must:
implement OAuth 2.1 for HTTP transport
implement Protected Resource Metadata (RFC9728) for authorization server discovery
supply a WWW-Authenticate header with the resource server metadata URL for 401 responses
Provide a client ID for interacting with the server if Dynamic Client Registration is not enabled
use the Authorization header for token handling
perform audience validation
include the resource parameter in authorization and token requests
implement precautions to prevent open redirects in the authorization flow
obtain user consent for every dynamically registered client when using a static client ID as a proxy to other services
MCP servers must not:
accept tokens not issued explicitly for the MCP server
use sessions for authentication
use deterministic session IDs
include authorization token in query strings
Client Requirements
Some of you may be working on LLM systems that include MCP support - congratulations, you are now a MCP client developer! There are important chunks of the specification that assume that there is a human in the loop for approvals: remote MCP servers are not great choices for things that are expected to be fully automated jobs (Quartz, cron, Celery, etc).
Clients must:
only expose filesystem roots with appropriate permissions
validate paths to prevent path traversal
monitor their access to their configured roots
Clients should:
implement user acceptance flows for sampling
implement user acceptance flows for elicitation
be clear about who is requesting information and why
allow users to refuse elicitation and/or sampling requests
MCP Server Cheatsheet
Transports
What transports are supported?
If HTTP transport is supported, are the network bindings acceptable?
If HTTP transport is supported, is the server doing origin validation?
Authorization/Authentication
Is the server authorized?
If authorization is enabled:
Is the server properly implementing OAuth 2.1?
Is the server performing audience validation?
Is the server using sessions for authentication purposes?
Is the server doing pass-through authorization?
Does the server support dynamic client registration?
MCP Features
Does the server support elicitation?
Does the server support sampling?
Does the server correctly query the client for roots when performing path operations?
Does the server properly prompt for consent before performing sampling or third party data transmission?
Are session IDs generated from a cryptographically secure pseudorandom number generator (CSPRNG)?
Are sessions reused?
Isolation and Sanitization
Does the server service multiple clients?
How is client data isolated from other requests?
Does the server perform path operations with client data?
Does the server perform shell operations with client data?
Does the server perform HTTP requests with client data?
Does the server perform FTP requests with client data?
Does the server perform LDAP requests with client data?
MCP Client Cheatsheet
This section covers auditing the MCP specification capabilities for MCP clients - generally things like Windsurf, Cursor, Claude Code, but may be any LLM-based MCP client.
Roots
Does the client support roots?
Does the client expose roots with appropriate permissions?
Does the client validate root URIs?
Does the client verify the accessibility of the root to the client?
Sampling
Does the client support sampling?
Does sampling always prompt a human for approval?
Does the client allow the user to preview the sampling response before sending it to the requestor?
Does the client have any special handling of potentially sensitive data?
Elicitation
Does the client support elicitation?
Does the client clearly display the server requesting an elicitation response?
Does the client allow the user to review and modify their response before submission?
Isolation and Sanitization
Does the client treat tool descriptions as untrusted?
Does the client treat tool output as untrusted?
How does the client handle name collisions?
Does the client always prompt for human approval on first-run?
Wrapping Up
With new capabilities of MCP come new integrations between software, which means new bugs. Go forth and use this knowledge to make your LLM ecosystem safer.
Download a copy of the Semgrep MCP Security Evaluation Cheatsheet to track your audit.
Happy securing!