Back to catalog
Season 59 14 Episodes 51 min 2026

MCP Security: Malicious Agent Skills

2026 Edition. Learn what peer-reviewed 2026 studies found in public agent-skill and MCP registries, how poisoned tool descriptions and leaked credentials reach an agent, and which MCP specification rules and local controls limit the damage.

AI Safety LLM Orchestration AI Development Methodology AI/ML Frameworks
MCP Security: Malicious Agent Skills
Now Playing
Click play to start
0:00
0:00
1
Skills vs MCP Servers
Agent skills and local MCP servers reach an agent through different paths: a skill puts its instructions in front of the model and runs its scripts, while a local server is launched as a child process over stdio. This episode shows why both run with the permissions of the user who launched them, and why the stdio transport is not an isolation boundary.
3m 52s
2
Registry Hijacking
A DSN 2026 study crawled 67,057 MCP servers across six public registries in mid-2025. It found 304 listings tied to renamed GitHub accounts and 212 tied to deleted ones, all claimable by someone else, plus maintainer tokens pasted into public configuration examples. This episode explains why a registry listing is not proof of who controls the code.
3m 15s
3
Malicious Skills in the Wild
Researchers scanned 98,380 agent skills from two public registries and confirmed 157 as malicious by running their scripts in a sandbox with fake credentials. This episode covers the two attacker types they found, the single publisher behind 54.1% of cases, and why most of the malicious content sat in SKILL.md prose rather than in code.
3m 59s
4
The Debug Print Leak
Agent frameworks capture what a skill prints and place it in the model's context. Using mock credentials in a sandbox, an ASE 2026 study found that debug output was the most common way skills exposed secrets. This episode traces one leftover debug line from a script into the conversation and covers the fixes the researchers recommend.
3m 44s
5
Leaked Secrets and Forks
An ASE 2026 study found that most skills with credential problems leaked them during ordinary use, and that secrets removed upstream survived in forks. This episode explains why fork-based distribution defeats code-level cleanup and why revoking the credential at its issuer is the fix that counts.
3m 55s
6
Dangling and Shadowed Tools
A DSN 2026 study tested four MCP hosts with models from three providers and found that the hosts invoke the tool the model names without checking it. This episode covers context-dangling tools left over in conversation history, and tool shadowing, where one server's description changes the parameters another server's tool receives.
3m 15s
7
How Tool Poisoning Works
Tool descriptions are loaded into the model's context before any tool runs, which makes them an instruction channel. This episode explains tool poisoning as defined by the MCPTox benchmark, how it differs from injection through tool outputs, and why the harmful call goes through a legitimate tool.
3m 38s
8
Inside the MCPTox Benchmark
This episode walks through MCPTox's three attack patterns and its results across 20 model settings. It keeps every number attached to its setup: older models, generic payloads, and a single benign request per test case.
4m 12s
9
Finding the Authorization Server
Remote MCP servers rely on OAuth 2.1 instead of a custom login scheme. This episode follows the first three steps of the 2026-07-28 authorization flow, from a 401 response to Protected Resource Metadata to the authorization server's own metadata, and the issuer check that protects the last step.
3m 19s
10
Client ID Metadata Documents
In the 2026-07-28 MCP specification, clients can identify themselves with an HTTPS URL that points to their metadata, and Dynamic Client Registration is deprecated. This episode covers what the authorization server checks, what a metadata document cannot prove for desktop clients, and the safeguards the specification expects.
3m 47s
11
SSRF in OAuth Discovery
This episode covers server-side request forgery during MCP's OAuth metadata discovery, where the client becomes the attacker's proxy inside your network. It walks through the mitigations in the MCP security best practices, from blocking private address ranges to checking redirects and guarding against DNS rebinding.
3m 38s
12
The Confused Deputy
MCP proxy servers that use one static client ID with a third-party API can become confused deputies. This episode explains the conditions that let a consent cookie approve the wrong client, and the per-client consent the MCP specification requires.
3m 55s
13
The Token Passthrough Anti-Pattern
Token passthrough means accepting a client's token without checking that it was issued for you, then forwarding it downstream. This episode covers audience validation with RFC 8707 resource indicators, the audit and trust problems passthrough creates, and why upstream calls need their own credentials.
3m 39s
14
Containing Local Servers
No install-time check proves what a local MCP server will do. This episode covers the controls from the MCP local server security guide that still hold when that check is wrong: process isolation, per-server credentials, narrow file access, and network egress limits.
3m 33s

Episodes

1

Skills vs MCP Servers

3m 52s

Agent skills and local MCP servers reach an agent through different paths: a skill puts its instructions in front of the model and runs its scripts, while a local server is launched as a child process over stdio. This episode shows why both run with the permissions of the user who launched them, and why the stdio transport is not an isolation boundary.

Download
Hi, this is Alex from DEV STORIES DOT EU. MCP Security: Malicious Agent Skills, episode 1 of 14. You might assume your AI framework places a protective shield around your local files when extending its capabilities. But under the hood, these extensions are just ordinary operating system processes running with your exact credentials. That brings us to how your agent actually gains new capabilities: Skills versus MCP Servers. According to two 2026 peer-reviewed papers on agent extension mechanisms, the first path into your agent is a skill. A skill operates as a file-based package. At the center of this package is a SKILL dot md file consisting of natural-language instructions. This text file is often packaged alongside helper scripts written in Python, shell, or JavaScript. At runtime, the agent framework takes those natural-language instructions and inserts them directly into the model's context. The model then follows those plain-text instructions and runs the attached helper scripts to complete tasks. This is the part that matters. The prose within that markdown file is an active instruction channel that directly steers the model. It is not just passive documentation for the user to read. Installing a skill typically grants it your full local privileges, and this process happens with very little review or confirmation from the user. The second path is a local MCP server, which is outlined in the 2026-07-28 edition of the MCP local server security guide. A local MCP server is not a magical AI construct. It is an ordinary program that the host application launches directly as a child process. Once launched, the host application and the server communicate entirely over stdio. The host writes messages into the child process's standard input and reads the replies from its standard output. You can picture two programs passing notes back and forth through a pipe. Because this interaction uses a formalized protocol, people occasionally assume the server runs inside a secure sandbox. That is incorrect. The stdio transport only carries messages between the programs. It is not a security boundary, and it provides zero isolation. The MCP guide explicitly states that the client and a stdio server share a single trust domain. Because the server is just a standard child process, it immediately inherits your environment variables. It can read absolutely anything your user account has permission to read. It also has the ability to open outbound network connections. There is nothing standing between the server process and your private files. Any actual isolation or sandboxing is completely up to the host application and whoever is running the machine. You can compare this to installing a command-line tool yourself. When you download and run a normal utility, you expect it to execute with your user account permissions. Letting your agent install a skill or start a local MCP server is fundamentally the exact same action. In every single case, the code simply runs as you. Ultimately, there are two distinct paths into your agent: prose that steers the model, and code that executes on your machine, and both paths carry your full privileges. If you enjoy the podcast and want to help support the show, you can find us by searching for DevStoriesEU on Patreon. That is all for this one. Thanks for listening, and keep building!
2

Registry Hijacking

3m 15s

A DSN 2026 study crawled 67,057 MCP servers across six public registries in mid-2025. It found 304 listings tied to renamed GitHub accounts and 212 tied to deleted ones, all claimable by someone else, plus maintainer tokens pasted into public configuration examples. This episode explains why a registry listing is not proof of who controls the code.

Download
Hi, this is Alex from DEV STORIES DOT EU. MCP Security: Malicious Agent Skills, episode 2 of 14. You click an install link on a public index, assuming the author still owns the code, but someone else silently took over the address. This is exactly how Registry Hijacking works. According to the peer-reviewed DSN 2026 paper A First Look at the Security Issues in the Model Context Protocol Ecosystem, researchers crawled about 67,000 MCP servers from six public registries in mid-2025. People often confuse a registry entry with a code audit, but registries primarily just list metadata. While npm and Smithery host the files themselves, four of the registries examined, including mcp dot so, mainly index links to code hosted elsewhere. That code almost always lives on GitHub. These registries accept listings without vetting. They do not re-check who controls a link after the initial submission, and they keep listing servers even when the original links go dead. This creates a specific vulnerability when a maintainer renames a GitHub account. GitHub frees up the old account name for anyone to register. The platform maintains redirects from the old name to the new one, but only until someone else claims the old name. Similarly, if an account is deleted entirely, its name becomes available for registration again after 90 days. If someone registers that old name, they immediately control what the original registry link serves. Whoever holds the name controls the repository contents, including the tool descriptions that users load into their agents. From the user side, the attack is invisible. You find a useful server on an MCP registry and follow the installation instructions. Because the original maintainer renamed their account, the registry link now points to a repository held by a completely different person. The link leads to whatever the new holder of the old name has published. The study measured the conditions that make this hijacking possible, not confirmed hijacks. Out of the crawled servers, researchers found 304 listings tied to renamed accounts and 212 tied to deleted ones. All of these were claimable by someone else. Hundreds of listings were vulnerable to takeover. To put that in perspective, out of the tens of thousands of servers examined, the researchers found only 18 servers that had tool descriptions containing suspicious, instruction-like text, and most of those were just proofs of concept. Those 18 instances were suspicious descriptions, not malicious uploads, and the study did not count malicious uploads. The data shows that the far larger, structural issue is the sheer volume of abandoned, claimable namespaces. A smaller second finding on mcp dot so involved configuration examples. Some maintainers pasted their own live GitHub tokens directly into their public configuration files. A few of these tokens still worked in July 2025. After disclosure, a recheck found none were still usable. A registry listing tells you where code was published, not who controls it today, so check the current repository owner and pin the version you reviewed. That is all for this one. Thanks for listening, and keep building!
3

Malicious Skills in the Wild

3m 59s

Researchers scanned 98,380 agent skills from two public registries and confirmed 157 as malicious by running their scripts in a sandbox with fake credentials. This episode covers the two attacker types they found, the single publisher behind 54.1% of cases, and why most of the malicious content sat in SKILL.md prose rather than in code.

Download
Hi, this is Alex from DEV STORIES DOT EU. MCP Security: Malicious Agent Skills, episode 3 of 14. Over half of all confirmed malicious agent skills in a recent study came from a single threat actor pumping out fake brand integrations. You might expect the danger to hide deep inside obfuscated Python files, but the primary attack vector is often plain English text. This is the reality of malicious skills in the wild. The facts for this episode come from a peer-reviewed USENIX Security 2026 paper titled Do Not Mention This to the User. The researchers took a January 2026 snapshot of more than 98,000 skills pulled from two major community registries. Their goal was to find intentionally malicious packages. It helps to clarify right away that these are not skills with accidental vulnerabilities or sloppy coding mistakes. These are skills built with deliberate malicious intent. To find them, the team started with static checks. They also used a language model to read every single SKILL dot md file across the dataset, specifically looking for manipulative instructions. That initial sweep flagged a few thousand candidates. The researchers then took each candidate and ran its scripts for 60 seconds in an isolated container, which they had seeded with fake credentials. Finally, two researchers manually reviewed every case that exhibited suspicious behavior during that time. They confirmed exactly 157 skills as intentionally malicious. The central finding from this analysis is where the actual malicious logic lives. About 84 percent of the vulnerabilities in those confirmed skills sat in the natural language SKILL dot md instructions. Less than a tenth resided in executable code. Two distinct types of attacker emerged from this group. Most fell into the Data Thieves category. These skills aim to steal data and credentials through a combination of hardcoded endpoints, remote script execution, and credential harvesting. A smaller, but highly focused group were the Agent Hijackers. These attacks work entirely through the SKILL dot md files. They target the agent's instruction-following logic directly. The text prompts explicitly tell the agent to override the user, to keep specific actions secret from the user, or to simply not ask the user for permission before acting. Scale was driven largely by automation. One publisher accounted for over half of the 157 confirmed skills, relying on a template that impersonated well-known brands to trick developers into installing them. The paper presents a clear example of how these payloads are delivered using a published finding called the math-calculator skill. The skill's description promises basic arithmetic functions, giving it a benign appearance. However, the associated calculate dot py script contains a reverse shell connecting back to a hardcoded address. There are strict limits to what these numbers represent. The count of 157 is a lower bound. When the researchers reviewed a separate sample of unconfirmed candidates, they found that most contained dormant triggers. The 60-second sandbox run simply never fired them. Additionally, the study never ran an AI agent with these skills installed. The research proves what these files contain and what the authors intend, but it does not measure how often an agent actually obeys the manipulative prompts. Registry maintainers removed all 157 skills after disclosure. The critical shift here is how you treat natural language files in your dependencies. You must review a skill's prose with the same suspicion as its code. That is all for this one. Thanks for listening, and keep building!
4

The Debug Print Leak

3m 44s

Agent frameworks capture what a skill prints and place it in the model's context. Using mock credentials in a sandbox, an ASE 2026 study found that debug output was the most common way skills exposed secrets. This episode traces one leftover debug line from a script into the conversation and covers the fixes the researchers recommend.

Download
Hi, this is Alex from DEV STORIES DOT EU. MCP Security: Malicious Agent Skills, episode 4 of 14. A developer prints a raw API response while debugging a database connection, forgets to remove the line, and that token instantly ends up inside a model's context window. The Debug Print Leak is the direct result of mixing standard coding habits with language model architecture. The details of this vulnerability come from the peer-reviewed ASE 2026 paper titled How Your Credentials Are Leaked by LLM Agent Skills. The authors sampled about 17,000 skills from the SkillsMP marketplace in February 2026. They executed these skills in Docker sandboxes using a Claude Code agent on default settings. By giving the skills mock credentials, the researchers could track exactly how and where those secrets surfaced. They found that most of the leaks did not stem from deliberate malice. Instead, they were caused by simple developer negligence. The single largest category of this negligence was debug output. Leftover print or console dot log statements made up 73.5 percent, or about three quarters, of the vulnerability issues in this study's sample. To understand why a simple debug line is catastrophic here, you have to look at the mechanics of the agent. Agent frameworks are designed to capture what a script writes to standard output and standard error. They take those output streams and place them directly into the model's context window so the agent knows what happened during execution. As a result, a printed secret sits fully exposed in the active conversation and its transcript. This is distinct from the problem of hardcoded secrets. When a secret is hardcoded, the developer has typed a password directly into the source code itself. In a debug leak, the secret is loaded properly at runtime from a secure environment variable or a vault. The vulnerability occurs entirely because the script prints that securely loaded value to the screen, where the agent framework scoops it up. Once the token is in the context window, anyone who can steer the agent can get the secret back with a plain-language request. The researchers confirmed this in their sandbox by planting instructions inside the content that a skill processed. If an agent reads a document containing malicious instructions, that injected input can command the agent to reveal the printed secret. The paper highlighted a Google Workspace skill that printed OAuth tokens to standard output. An attacker only needed to feed the agent a document that asked for the token to extract it. Scanners struggle to catch this. The study found that most leaks could only be identified by reading a skill's natural language instructions and its programming logic together. Traditional security scanners that read only the code completely miss these vulnerabilities, because a print statement is not inherently malicious syntax. The researchers assign responsibility for fixes to both sides of the ecosystem. Skill developers should keep secrets out of what they print and run secret scanning before they publish. Agent frameworks should strip recognized credential patterns from output streams before that text ever reaches the model. The study does have limits. It covers a single marketplace, relies entirely on mock credentials, and it does not report any real-world abuse of leaked keys. Regardless of those limits, the core architectural truth remains unchanged. In an agent, standard output is model input. That is all for this one. Thanks for listening, and keep building!
5

Leaked Secrets and Forks

3m 55s

An ASE 2026 study found that most skills with credential problems leaked them during ordinary use, and that secrets removed upstream survived in forks. This episode explains why fork-based distribution defeats code-level cleanup and why revoking the credential at its issuer is the fix that counts.

Download
Hi, this is Alex from DEV STORIES DOT EU. MCP Security: Malicious Agent Skills, episode 5 of 14. When security researchers disclosed vulnerabilities to developers, maintainers across 107 repositories quickly removed hardcoded credentials from their codebase. Yet, those exact same credentials were still present in more than 50 independent forks, counted together across all 107 of those repositories. You can easily clean up your own main codebase, but you cannot unilaterally scrub the decentralized copies scattered across other accounts. That is the core dynamic of Leaked Secrets and Forks. The data explaining this distribution behavior comes from the peer-reviewed ASE 2026 paper titled "How Your Credentials Are Leaked by LLM Agent Skills." The researchers conducted a broad analysis, studying about 17,000 skills sourced from the SkillsMP marketplace. To track how these exposures happen safely, they evaluated the agent skills using mock credentials operating within a controlled sandbox environment. This study has clear limits: it covers one marketplace, its tests used mock credentials, and it reports no real-world abuse of leaked keys. Even with those specific boundaries, the exploitability metrics observed in the sandbox establish a very clear baseline. The tests showed that nearly nine in ten of the affected skills, exactly 89.6 percent, leaked a credential during normal execution. Triggering this exposure required no elevated privileges from the user. A leak is likely during ordinary use, and once a secret is out, cleanup in the code is the hard part. The difficulty of cleanup stems directly from how open-source agent skills are distributed and copied across the ecosystem. People often assume a swift platform intervention solves the problem. It does not. Removal from a registry takes down the listing, but it cannot reach forks or copies already on other machines. During the study, the marketplace removed all the malicious skills the researchers reported. In one specific reported case, maintainers entirely banned the publisher of a malicious skill from the platform. Despite these aggressive centralized actions, copies of the affected code kept spreading through independent forks. Consider the standard lifecycle of an exposed key in this environment. A developer hardcodes a client secret directly in an agent skill to get a feature working quickly. Later on, they realize the security risk they created. They delete the secret from the main repository. They might even use version control commands to rewrite the repository history, completely obliterating the commit that originally introduced the key. However, forks do not synchronize deletions. Because of how the architecture handles cloning, an upstream fix simply does not reach the copies. Those cloned files remain entirely intact in forks the original developer does not control. This structural reality dictates how you must handle remediation when a leak occurs. Deleting the text of the key or rewriting your repository history does not actually invalidate the exposed credential. The only fix that counts is revoking or rotating the secret at the service that originally issued it. You must perform this rotation immediately upon discovering the exposure, without waiting for any evidence of misuse. Erasing a committed token from your repository history only patches your personal branch, but revoking the token at the service provider immediately nullifies the threat across every copied fork in existence. That is all for this one. Thanks for listening, and keep building!
6

Dangling and Shadowed Tools

3m 15s

A DSN 2026 study tested four MCP hosts with models from three providers and found that the hosts invoke the tool the model names without checking it. This episode covers context-dangling tools left over in conversation history, and tool shadowing, where one server's description changes the parameters another server's tool receives.

Download
Hi, this is Alex from DEV STORIES DOT EU. MCP Security: Malicious Agent Skills, episode 6 of 14. If an AI model decides to invoke a tool that has already been deleted from your system, the host application will still try to run it. The host software blindly trusts the output of the model, which creates a critical verification gap. Today we look at how that gap enables dangling and shadowed tools. The details come from the peer-reviewed DSN 2026 paper titled A First Look at the Security Issues in the Model Context Protocol Ecosystem. The authors tested four MCP hosts, including Cursor and Claude Desktop, using models from OpenAI, Anthropic, and Google. They executed five runs per pairing. These runs show that the security issues are feasible, not necessarily how often they happen in real environments. We need to clarify the exact roles in this ecosystem before looking at the attacks. The language model never executes any code itself. The model only chooses a tool and its parameters. The host then passes that call to the server, and the server runs the tool's code. The core finding of the research is that the hosts invoked whatever tool the model named without checking it independently. The first consequence of this missing check is the context-dangling tool. After a server is removed from your environment, an old conversation history still mentions its tools. When the model processes the conversation, it finds no match in the current active tool list. It simply picks the old tool from the history. Because none of the hosts checked whether that tool still existed, they attempted to invoke it. The call inevitably fails. That failure message goes back to the model, which may then get confused and choose an entirely wrong tool for its next step. The second consequence is tool shadowing. Before making a decision, the model reads every single tool description provided by the servers. Because the model processes all descriptions together, one server's description can change how the model fills in parameters for another server's tool. In a shadowing attack, the shadowing tool itself is never actually invoked. Consider a threat model involving two tools. You have a legitimate database tool with an injection flaw. You then install a second, newly added server. The attacker controls this new server and writes a tool description designed to steer the query parameters. When the model decides to query the database, it uses the legitimate tool, but it shapes the parameters based on the attacker's description. The host passes this call without verifying the context. Those manipulated parameters reach the flaw in the legitimate database tool. Out of the tested hosts, only Claude Desktop did some parameter validation, and it applied it inconsistently. The other hosts just forwarded the parameters exactly as the model provided them. This is the part that matters. You must always treat the model's tool call as completely untrusted input and validate it before the host passes it on to the server. By the way, if you want to help support the show, you can search for DevStoriesEU on Patreon. That is all for this one. Thanks for listening, and keep building!
7

How Tool Poisoning Works

3m 38s

Tool descriptions are loaded into the model's context before any tool runs, which makes them an instruction channel. This episode explains tool poisoning as defined by the MCPTox benchmark, how it differs from injection through tool outputs, and why the harmful call goes through a legitimate tool.

Download
Hi, this is Alex from DEV STORIES DOT EU. MCP Security: Malicious Agent Skills, episode 7 of 14. A malicious server connects to your system, and without executing a single line of code, it forces your AI agent to read your private SSH keys. The vulnerability lies entirely in how your agent plans its actions. Today we cover How Tool Poisoning Works to explain exactly how that happens. Our focus is the MCPTox benchmark paper, peer reviewed and published at AAAI 2026. To understand the attack, you have to look at what happens when a client connects to a server. Each server provides a list of its available tools, including their names and descriptions. The client takes these tool names and descriptions and loads them directly into the model's context or system prompt, ensuring the agent is aware of every possible action it can take. When a user makes a request, the model reads all of them when it plans its next steps. Tool poisoning hides instructions in a tool's description. It is a specialized form of indirect prompt injection. Listeners commonly confuse the two, but they operate at entirely different stages of the execution cycle. Classic indirect injection arrives inside a tool's output after a tool runs. Tool poisoning arrives with the tool list before any tool runs. The paper showed that the channel matters. Payloads taken from an output-injection benchmark and moved into tool descriptions almost never worked, so poisoned descriptions have to be written for that channel. This is the part that matters. In the MCPTox benchmark, the poisoned tool is never executed. The attack succeeds purely by manipulating the agent's context and planning phase, forcing it to use a different, legitimate high-privilege tool maliciously. An attack counts as successful only when the agent calls a different, legitimate tool to do what the poisoned description asked. Consider a specific scenario from the published findings. An attacker registers a fake tool named security check. The poisoned description for this tool claims that every single file operation requires reading the user's SSH private key first. The user asks the agent to create a file. During the planning phase, the agent reads the descriptions of all available tools to figure out how to do the task. It sees the security check description, assumes the instruction is a system requirement, and complies. The agent calls the legitimate file-reading tool on the key before doing the requested task. The benchmark scores the tool call the agent makes and does not measure real data loss, so the result demonstrates the agent reading the key, not that the key leaves the machine. Defending against this requires intercepting the attack at two points. First, scan tool descriptions for imperative instructions when a server is registered. Second, check each tool call against the user's actual request before it runs. A tool description is an instruction channel, so trust it no more than the server that wrote it. If you have a moment and want to support the show, you can find us by searching for DevStoriesEU on Patreon. That is all for this one. Thanks for listening, and keep building!
8

Inside the MCPTox Benchmark

4m 12s

This episode walks through MCPTox's three attack patterns and its results across 20 model settings. It keeps every number attached to its setup: older models, generic payloads, and a single benign request per test case.

Download
Hi, this is Alex from DEV STORIES DOT EU. MCP Security: Malicious Agent Skills, episode 8 of 14. In the MCPTox benchmark, the poisoned tool never actually runs. The attack succeeds without executing any malicious payload directly, because all the harm is delivered through a legitimate tool the agent already trusts. Inside the MCPTox Benchmark, we see exactly how rogue tool descriptions weaponize an agent's own behavior. Published at AAAI 2026, MCPTox provides a structured evaluation of these vulnerabilities. The researchers built over 1,300 poisoned-tool test cases across 45 live Model Context Protocol servers. They ran these tests against 20 model settings, focusing mostly on older models like o1 mini and Claude 3.7 Sonnet. The testing method isolates the exact moment of failure. Each test places a single poisoned tool alongside a server's legitimate tools. The benchmark then sends one benign user request and records which tool the model calls, along with the specific parameters it uses. When an attack succeeds, the poisoned tool stays dormant while a legitimate tool does the actual harm. The benchmark identifies three distinct attack patterns. First is explicit-trigger function hijacking. In this setup, the poisoned tool imitates a common, benign function, such as getting the current time. When the user asks for exactly that function, the agent reads the poisoned tool's description. That description contains an explicit rule instructing the agent to abandon the time request and instead call a different, high-privilege legitimate tool. The second pattern is implicit-trigger function hijacking. Here, the poisoned tool poses as a background process rather than a directly callable function. Its hidden rule is designed to fire whenever the user performs a related kind of action. The agent reads the background tool's description during its planning phase, and the hidden rule triggers the hijack even though the user never asked for that specific tool. The third pattern is implicit-trigger parameter tampering. A listener might confuse this with user prompt injection, but the tampering instruction is hidden entirely in the server's tool metadata. A rule simply changes the parameters of a legitimate call. For a concrete scenario, a user asks the agent to send an email. A rule hidden in an entirely unrelated tool's description makes the agent put a different, attacker-controlled recipient into the email tool's call. The agent dutifully uses the correct tool, but manipulates the data passing through it. Parameter tampering proved to be the most effective pattern in the benchmark. This is the part that matters. The average attack success rate across all settings was 36.5 percent, and the highest was o1 mini at 72.8 percent. Across the mostly older models it tested, MCPTox found that more capable models were often more susceptible, which the authors attribute to stronger instruction following. In the Qwen3 family, turning on reasoning raised the attack success rate. Model safety behaviors rarely intervened. No model itself refused more than 3 percent of attacks. Because the requested actions utilize legitimate, authorized tools, the models do not recognize the malicious intent. Note the limits of this benchmark. The tests used older models, generic payloads that were not adapted to any defense, and only one benign request per test case, so these numbers are not exact rates for current models. If you find these episodes helpful, you can support the show by searching for DevStoriesEU on Patreon. The poisoned tool never has to run, because the damage arrives through a legitimate tool call, so that call is the place to check. Thanks for listening. Take care, everyone.
9

Finding the Authorization Server

3m 19s

Remote MCP servers rely on OAuth 2.1 instead of a custom login scheme. This episode follows the first three steps of the 2026-07-28 authorization flow, from a 401 response to Protected Resource Metadata to the authorization server's own metadata, and the issuer check that protects the last step.

Download
Hi, this is Alex from DEV STORIES DOT EU. MCP Security: Malicious Agent Skills, episode 9 of 14. When a client connects to a remote server for the first time, it has absolutely no reason to trust it. The server will demand authentication, but if the client blindly follows the server's instructions on where to log in, it can easily be tricked into handing credentials to an attacker. Resolving this tension relies on a process called Finding the Authorization Server. Authorization in the Model Context Protocol applies strictly to servers reached over HTTP. Local standard input and output servers simply take credentials from their environment instead. For remote connections, MCP does not invent a new login scheme. It builds directly on OAuth 2.1 and existing RFCs to handle identity and access. The primary challenge during discovery is that every pointer the client receives comes from a server it does not trust yet. The flow begins when a client sends a request to a remote MCP server without an access token. Because the endpoint is protected, the server replies with a 401 Unauthorized status code. Alongside this rejection, the server includes a WWW Authenticate header. Inside this header is a resource metadata parameter. This parameter holds the web address of the server's Protected Resource Metadata document, which is defined in RFC 9728. If the server leaves this parameter out of the header, the client must fall back and try standard well known addresses to locate the document instead. Once the client has the correct address, it fetches the Protected Resource Metadata document from the resource server. This document provides three specific pieces of information. It names the protected resource, lists the supported authorization scopes, and provides the address for at least one authorization server. This document does not contain the authorization endpoint, and it does not contain the token endpoint. It only tells the client which authorization server is in charge of protecting the requested data. The client now has an authorization server address, but it still needs to know exactly where to send the login request. To find out, it takes the authorization server address and builds its well known metadata address. It does this using the standard paths defined by OAuth 2.0 Authorization Server Metadata or OpenID Connect Discovery. The client then fetches this second metadata document directly from the authorization server. This second document is the one that holds the actual authorization endpoint and the token endpoint. Before the client can safely use those endpoints, it must verify the document's origin. The client checks that the issuer value written inside the document exactly matches the issuer address it used to build the request in the first place. If a document served from one host claims to be a different, honest issuer, the client must reject it immediately. Ultimately, discovery hands the client a chain of pointers, and the strict issuer check stops a metadata document from claiming to be a different authorization server. Thanks for listening. Take care, everyone.
10

Client ID Metadata Documents

3m 47s

In the 2026-07-28 MCP specification, clients can identify themselves with an HTTPS URL that points to their metadata, and Dynamic Client Registration is deprecated. This episode covers what the authorization server checks, what a metadata document cannot prove for desktop clients, and the safeguards the specification expects.

Download
Hi, this is Alex from DEV STORIES DOT EU. MCP Security: Malicious Agent Skills, episode 10 of 14. In distributed networks, it is relatively straightforward to prove that a developer controls a specific web domain. It is significantly harder to prove that the local application requesting access on a user machine is actually the program it claims to be. This distinction is central to understanding Client ID Metadata Documents. Before a client can authorize with an authorization server, it needs a client ID. According to the specification edition 2026-07-28, there are three ways to establish this identity. The primary method is pre-registration. Clients should always use pre-registered details when they have them. The second method is a Client ID Metadata Document, which should be used when the authorization server advertises support for it. The third method is Dynamic Client Registration. Dynamic Client Registration is now deprecated in this edition and is kept solely for backward compatibility with authorization servers that do not support metadata documents. When relying on a metadata document, the process operates without any prior enrollment. The developer of the client publishes a JSON document at a fixed HTTPS URL that includes a specific path. This URL itself serves as the client ID. Inside that JSON document, there are required fields. The document must contain the client ID, the client name, and a list of allowed redirect URIs. The client ID defined inside the JSON document must match the hosting URL exactly. When the client encounters an authorization server for the first time, it submits that HTTPS URL as its client ID. The authorization server takes that URL, fetches the JSON document, and verifies the exact match. It then checks the redirect URI provided in the client request against the list of allowed URIs in the document. This design introduces specific threat models that require attention. First, the authorization server is fetching a URL chosen by an unknown client. This exposes the server to server-side request forgery. To mitigate this risk, the authorization server should block requests to private network addresses. The second threat model involves the redirect process. Consider a desktop MCP client that redirects to a localhost address to complete its authorization flow. The metadata document successfully proves that the developer controls the domain hosting the JSON file. What it cannot prove is which program is currently listening on the localhost redirect address. It does not by itself make a client trustworthy. The specification warns about local spoofing. Another local program running on the same machine can present the legitimate client metadata URL while supplying its own localhost redirect port. If the server accepts this, the user is presented with the legitimate client name on the consent screen, even though the authorization code will be sent to the malicious program. Because of this threat, authorization servers are expected to implement specific defenses. They should show extra warnings for localhost-only redirect URIs. They must also clearly display the redirect URI host during the authorization process so the user can verify it. Additionally, servers may apply broader trust policies, such as domain allowlists, to restrict which metadata domains they will process. Ultimately, a metadata document proves who controls a domain, not which program you are talking to. Thanks for listening. Take care, everyone.
11

SSRF in OAuth Discovery

3m 38s

This episode covers server-side request forgery during MCP's OAuth metadata discovery, where the client becomes the attacker's proxy inside your network. It walks through the mitigations in the MCP security best practices, from blocking private address ranges to checking redirects and guarding against DNS rebinding.

Download
Hi, this is Alex from DEV STORIES DOT EU. MCP Security: Malicious Agent Skills, episode 11 of 14. Before it can log in, a client must fetch metadata URLs that the server hands it. But blindly following a map drawn by an unknown party can force your system to attack its own internal network. The vulnerability that causes this is SSRF in OAuth Discovery. Our primary source for this behavior is the MCP security best practices, edition 2026-07-28. When dealing with Server-Side Request Forgery, you usually expect the server to be the targeted system. Here the attacker is the server and the victim is the client. Authorization servers that fetch Client ID Metadata Documents face the same risk, from malicious clients. During OAuth discovery, an MCP client fetches URLs that a malicious MCP server controls. The attacker has several places to inject these addresses. The malicious server provides the resource metadata address that the client reads from the WWW-Authenticate header. It provides the authorization server addresses located within the Protected Resource Metadata. It also controls the endpoints listed in the authorization server's metadata. A malicious server can point them at internal IP addresses, at localhost services, or at the cloud metadata address, one sixty-nine dot two fifty-four dot one sixty-nine dot two fifty-four. To understand the impact, look at this scenario presented as a threat model only. An MCP client running on a cloud virtual machine connects to an untrusted server. This untrusted server points a metadata URL directly at the cloud metadata address. Cloud metadata services often expose IAM credentials. When the client queries that address, internal responses can leak back to the attacker. This leakage happens either through error messages or through the execution of the OAuth flow itself. In effect, the client becomes a proxy past network perimeter controls. The guidance states one hard requirement in this section. MCP clients deployed to a server must consider this risk and put mitigations in place that fit their network. To achieve this, the documentation recommends four specific mitigations. For the first mitigation, clients should require HTTPS for these URLs in production and allow plain HTTP only for loopback addresses during development. For the second mitigation, clients should block private, loopback, and link-local ranges, including private IPv6 ranges. The guidance specifically advises against hand-written IP checks because attackers use alternative IP encodings that custom parsers miss. For the third mitigation, clients should apply the same checks to every redirect hop. Furthermore, the guidance suggests considering pinning the resolved address between the check and the request, because a domain can resolve to a safe address during the check and to an internal one when the request is made. For the fourth mitigation, operators of server-side deployments should consider an egress proxy that blocks internal destinations. The underlying problem is that in discovery the server chooses the destination and your client makes the request, so every URL from a server is untrusted input. Thanks for listening, happy coding everyone!
12

The Confused Deputy

3m 55s

MCP proxy servers that use one static client ID with a third-party API can become confused deputies. This episode explains the conditions that let a consent cookie approve the wrong client, and the per-client consent the MCP specification requires.

Download
Hi, this is Alex from DEV STORIES DOT EU. MCP Security: Malicious Agent Skills, episode 12 of 14. An attacker can steal your API access by tricking a proxy server into doing their dirty work for them, all because of a leftover browser cookie. The Confused Deputy is the problem that allows this to happen. In this architecture, a Model Context Protocol proxy server sits in front of a third-party API. Toward the third-party authorization server, the proxy acts as a single OAuth client. It uses one static client ID for all communication. Toward its own users, the proxy operates differently. It lets MCP clients register dynamically, meaning each client gets its own unique client ID at the proxy level. The dynamic registration happens exclusively at the MCP proxy. The third-party authorization server remains entirely unaware of these individual clients, because it only knows the proxy's static client ID. Sometimes this mechanism gets confused with another attack type. Server-side request forgery abuses network requests, while the confused deputy abuses consent in the user's browser. The problem requires four specific conditions to exist together. First, you have the static client ID connecting the proxy to the third party. Second, you have dynamic registration happening at the proxy. Third, there is a consent cookie that the third-party authorization server sets after a user gives their first approval. Fourth, the proxy forwards requests to the third party without asking for consent per client. The threat model flows directly from these conditions. A user approves access for a legitimate application once, so the third-party server remembers this consent for the proxy's static client ID and sets the cookie. Later, an attacker registers a new malicious client. This malicious client receives its own redirect address. The attacker then gets the user to open an authorization link tied to this malicious client. When the user clicks the link, their browser makes a request to the third-party server and includes the existing consent cookie. The third-party server sees the cookie and immediately skips its consent screen, assuming the user already approved this access. The item that gets redirected back is an authorization code. Because the malicious client supplied its own address during the dynamic registration, the authorization code is redirected to the attacker's registered address. The attacker takes that code, exchanges it for tokens, and reaches the third-party API masquerading as that user. The proxy server gets tricked into using its static privileges on behalf of a malicious client, highlighting a failure of authorization rather than identity. The root cause is clear. Consent is tied to the proxy's shared client ID instead of to each individual client. The specification dictates how to fix this. MCP proxy servers using static client IDs must obtain the user's consent for each dynamically registered client before forwarding anything to the third-party authorization server. There are two supporting rules required to enforce this security model. Consent cookies, if used, must be bound to the specific client ID. Furthermore, redirect URIs must match the registered value exactly. Consent must belong to a specific client, or one approval can authorize the wrong one. If you would like to support the show, you can search for DevStoriesEU on Patreon. Thanks for listening. Take care, everyone.
13

The Token Passthrough Anti-Pattern

3m 39s

Token passthrough means accepting a client's token without checking that it was issued for you, then forwarding it downstream. This episode covers audience validation with RFC 8707 resource indicators, the audit and trust problems passthrough creates, and why upstream calls need their own credentials.

Download
Hi, this is Alex from DEV STORIES DOT EU. MCP Security: Malicious Agent Skills, episode 13 of 14. Passing an authentication token straight down the chain to a backend API might seem like clean, efficient engineering. But doing so completely shatters your security boundary and hides accountability. This is called The Token Passthrough Anti-Pattern. Developers often treat intermediate services as pure proxies. The logic usually goes that if the client already authenticated, you can just forward their token downstream to keep the architecture simple. That is a mistake. Forwarding an incoming token breaks the OAuth security model. When an MCP server receives a token from a client, that token represents an agreement between the authorization server and the client, intended specifically for that MCP server. If your server takes that token and hands it off to a third-party API, the downstream system loses critical context. The backend API thinks the original client made the request directly. The MCP server vanishes from the audit log. You have bypassed your own accountability controls. Consider what happens when this goes wrong. An attacker manages to steal a token originally minted for a harmless, low-privilege service. They take this stolen token and send it to your MCP server. Your server does not verify if the token was actually meant for it. It just checks if the signature is valid, accepts it, and then proxies a request to a high-privilege downstream database API, attaching the stolen token. The downstream database accepts it, assuming the request is legitimate. The attacker just escalated their privileges because your server acted as a blind courier. To stop this, an MCP server must strictly validate that the token was minted specifically for it. This relies on Token Audience Binding, using RFC 8707 Resource Indicators. When an authorization server issues a token, it includes an audience claim, represented by the letters A, U, D in the token payload. This claim explicitly lists the intended recipients. When your MCP server receives a request, it must extract the token and inspect that audience claim. If the server's own identifier is not in that list, it must immediately reject the request. It does not matter if the cryptographic signature is mathematically perfect. If the token was not addressed to your server, it is invalid for your server. Checking the audience stops attackers from reusing tokens scraped from other, unrelated parts of your infrastructure. This is the part that matters. Once your server successfully validates the token and confirms it is the correct audience, that token's journey ends. It stops right there. If your MCP server needs to communicate with a backend API to fulfill the client request, it must never forward that original token. Instead, your server must authenticate with the downstream backend using its own distinct credentials, or perform a formal token exchange to get a new token specifically minted for the downstream service. The chain of identity must remain explicit at every single hop. By enforcing audience validation and stopping token passthrough, you maintain a verifiable chain of trust where every service knows exactly who is calling it. Never let your server act as an unquestioning middleman for someone else's credentials. Thanks for hanging out. Hope you picked up something new.
14

Containing Local Servers

3m 33s

No install-time check proves what a local MCP server will do. This episode covers the controls from the MCP local server security guide that still hold when that check is wrong: process isolation, per-server credentials, narrow file access, and network egress limits.

Download
Hi, this is Alex from DEV STORIES DOT EU. MCP Security: Malicious Agent Skills, episode 14 of 14. You write a strict configuration allowlist to keep a third-party process in check, assuming it forms a hard security boundary. But configuration allowlists are cooperative boundaries that only honest processes respect, leaving your system exposed if the code decides to ignore those rules. The only way to enforce those boundaries is by Containing Local Servers. According to the MCP Local Server Security guide, a local MCP server is an ordinary process your host application launches under your user account. Because it runs under your user account, it has your account's access. The server automatically inherits your environment variables, it can read whatever files your account can read, and it can freely open outbound network connections. It is a common misconception that the transport layer provides safety. The stdio transport only carries messages and is not a sandbox. The guide establishes a core principle: no check proves what a server will do. Checking provenance and pinning versions still matter alongside containment. However, vetting lowers the odds of a bad trust decision, and containment decides what a bad one costs. Because configuration allowlists only work when a server chooses to cooperate, real enforcement comes from the isolation layer. Implementing this isolation relies on three specific controls. First is the isolation environment itself. You run third-party servers in a container with nothing mounted except the directory they need. The guide says a container is not an impenetrable boundary, but it removes the default access to your environment, your files, and your keychain, which is what common attacks rely on. Containment reduces what a compromise can reach. It limits damage and is never a guarantee. The second control is managing credentials. You must give each server its own narrowly scoped token through the client's per-server configuration, instead of exporting secrets globally from your shell profile. You also need to remember that credential files, such as your SSH and cloud credential folders, count too. They must be kept out of the server's reach. The third control is managing egress. You run servers with no network access unless they need it. When a server does require network access, you limit the others to their expected destinations through an egress proxy with a domain allowlist that logs attempts outside it. To see why this matters, look at two different approaches. In the first case, a developer's shell profile exports every cloud key, so every local server they run can read all of those keys. In the second case, the server runs in a container with one scoped token, one mounted directory and no network, so a compromise is limited to what is mounted and what that one token allows. As we look back on this series, we have covered many ways agents and servers can act unpredictably. The final takeaway for this course is this: vetting lowers the odds, and containment limits the cost. I highly encourage you to read the MCP local server security guide, to try these controls hands-on in an isolated setup, and to visit devstories dot eu to suggest topics for future series. Thanks for spending a few minutes with me. Until next time, take it easy.