auditing-mcp-servers-for-tool-poisoning

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Auditing MCP Servers for Tool Poisoning

审计 MCP 服务器以防范工具投毒

Authorized-use-only notice: Auditing MCP servers can connect to and probe live tool endpoints. Only scan servers you own or are authorized to assess. Treat scanned tool descriptions as untrusted input — do not load an unaudited MCP server into a privileged agent. Probing third-party MCP endpoints for SSRF or auth weaknesses without permission may be illegal.
仅限授权使用声明: 审计 MCP 服务器可能会连接并探测实时工具端点。仅扫描您拥有或已获得授权评估的服务器。应将扫描到的工具描述视为不可信输入——不要把未经审计的 MCP 服务器加载到高权限 Agent 中。未经许可探测第三方 MCP 端点的 SSRF 或认证缺陷可能违法。

Overview

概述

The Model Context Protocol (MCP) lets AI agents discover and call external tools advertised by MCP servers. Each tool exposes a name and a natural-language description that the agent's LLM reads before deciding to call it. In early 2025, Invariant Labs disclosed that this description field is an attack surface: a malicious server can embed hidden instructions in a tool's description (a tool poisoning attack, OWASP MCP03:2025), and a capable model will silently follow them — exfiltrating files, leaking secrets, or redirecting tool calls — while returning a normal-looking response to the user. Because tool descriptions are loaded into the agent's context, tool poisoning is effectively indirect prompt injection delivered through the supply chain (MITRE ATLAS AML.T0010 ML Supply Chain Compromise).
Beyond poisoning, MCP servers introduce classic infrastructure risks: tool shadowing (a malicious server overrides a trusted tool's behavior), rug pulls (a tool's description changes after the user approved it), toxic flows (a combination of tools that enables data exfiltration), SSRF in tools that fetch URLs server-side, and unauthenticated exposure of MCP servers bound to network interfaces. This skill audits MCP servers end-to-end using Invariant Labs' mcp-scan for static and runtime analysis, plus manual checks for SSRF and authentication, and tool pinning to catch rug pulls.
Model Context Protocol (MCP) 让 AI Agent 能够发现并调用 MCP 服务器公布的外部工具。每个工具都公开一个名称和一段自然语言 描述,Agent 的 LLM 会在决定调用之前读取这段描述。2025 年初,Invariant Labs 披露这一描述字段构成攻击面:恶意服务器可以在工具描述中嵌入隐藏指令(即 工具投毒攻击,OWASP MCP03:2025),而能力足够强的模型会悄然执行这些指令——在向用户返回外观正常的响应时,将文件外传、泄露机密或重定向工具调用。由于工具描述会被加载到 Agent 的上下文中,工具投毒实际上是通过供应链投递的间接提示注入(MITRE ATLAS AML.T0010 ML Supply Chain Compromise)。
除投毒之外,MCP 服务器还会引入经典的基础设施风险:工具遮蔽(tool shadowing)(恶意服务器覆盖可信工具的行为)、rug pull(用户批准后工具的描述发生变化)、有毒流程(toxic flow)(某种工具组合可用于数据外传)、获取 URL 的工具中的 SSRF,以及绑定到网络接口的 MCP 服务器的未认证暴露。本 skill 使用 Invariant Labs 的 mcp-scan 对 MCP 服务器进行端到端审计,执行静态和运行时分析,并结合 SSRF 与认证的手动检查以及工具固定,以检测 rug pull。

When to Use

使用时机

  • Before adding a new MCP server to an agent stack (Claude Desktop, Cursor, VS Code, Windsurf, custom agents).
  • During a security review of an internally developed MCP server.
  • When validating that approved tools have not silently changed (rug-pull detection).
  • As a CI/CD gate that scans MCP configs and SKILL/tool definitions on every change.
  • During incident response when an agent took unexpected actions consistent with a poisoned tool.
  • 在将新的 MCP 服务器添加到 Agent 技术栈(Claude Desktop、Cursor、VS Code、Windsurf、自定义 Agent)之前。
  • 对内部开发的 MCP 服务器进行安全审查时。
  • 在验证已批准工具未被静默更改(rug-pull 检测)时。
  • 作为 CI/CD 门禁,在每次变更时扫描 MCP 配置和 SKILL/工具定义。
  • 在事件响应期间,当 Agent 执行了与工具投毒相符的意外操作时。

Prerequisites

前置条件

  • Python 3.10+ and
    uv
    (for
    uvx
    ), or pip.
  • The MCP config file(s) you want to scan (e.g.
    ~/.cursor/mcp.json
    ,
    ~/.vscode/mcp.json
    , Claude Desktop config).
  • Install the tooling:
bash
undefined
  • Python 3.10+ 和
    uv
    (用于
    uvx
    ),或者 pip。
  • 希望扫描的 MCP 配置文件(例如
    ~/.cursor/mcp.json
    、
    ~/.vscode/mcp.json
    、Claude Desktop 配置)。
  • 安装以下工具:
bash
undefined

uv provides uvx (recommended runner for mcp-scan)

uv provides uvx (recommended runner for mcp-scan)

curl -LsSf https://astral.sh/uv/install.sh | sh # or: pipx install uv
curl -LsSf https://astral.sh/uv/install.sh | sh # or: pipx install uv

mcp-scan (Invariant Labs) — no global install needed with uvx

mcp-scan (Invariant Labs) — no global install needed with uvx

uvx mcp-scan@latest --help
uvx mcp-scan@latest --help

For the runtime proxy mode (separate extra)

For the runtime proxy mode (separate extra)

uvx --with "mcp-scan[proxy]" mcp-scan@latest proxy --help
uvx --with "mcp-scan[proxy]" mcp-scan@latest proxy --help

Manual probing helpers

Manual probing helpers

pip install requests mcp
undefined
pip install requests mcp
undefined

Objectives

目标

  • Statically scan all installed MCP servers for tool poisoning, shadowing, rug pulls, and toxic flows.
  • Inspect raw tool/prompt/resource descriptions for hidden or obfuscated instructions.
  • Pin tool hashes to detect post-approval description changes (rug-pull defense).
  • Test URL-fetching tools for server-side request forgery (SSRF).
  • Verify MCP servers are authenticated and not exposed on untrusted interfaces.
  • Optionally enforce runtime guardrails with the mcp-scan proxy.
  • 静态扫描所有已安装的 MCP 服务器,检测工具投毒、工具遮蔽、rug pull 和有毒流程。
  • 检查原始工具/提示/资源描述中是否存在隐藏或混淆的指令。
  • 固定工具哈希,以检测批准后的描述变更(rug-pull 防御)。
  • 测试获取 URL 的工具是否存在服务器端请求伪造(SSRF)。
  • 验证 MCP 服务器具有身份认证,且未暴露在不可信接口上。
  • 可选地使用 mcp-scan proxy 实施运行时护栏。

MITRE ATT&CK Mapping

MITRE ATT&CK 映射

IDOfficial NameRelevance
AML.T0010ML Supply Chain CompromiseA poisoned third-party MCP server is a supply-chain compromise of the agent
AML.T0051.001LLM Prompt Injection: IndirectPoisoned tool descriptions are indirect injection into the agent context
AML.T0053LLM Plugin CompromiseMCP tools are the agent's plugins; poisoning compromises them
AML.T0057LLM Data LeakageCommon payload of a poisoned tool: exfiltrate files/secrets
ID官方名称关联性
AML.T0010ML Supply Chain Compromise(ML 供应链失陷)被投毒的第三方 MCP 服务器构成 Agent 的供应链失陷
AML.T0051.001LLM Prompt Injection: Indirect(LLM 提示注入:间接)被投毒的工具描述是对 Agent 上下文进行的间接注入
AML.T0053LLM Plugin Compromise(LLM 插件失陷)MCP 工具相当于 Agent 的插件;工具投毒会破坏这些插件
AML.T0057LLM Data Leakage(LLM 数据泄露)被投毒工具的常见载荷:外传文件和机密

Workflow

工作流

1. Static scan of installed MCP configs

1. 对已安装的 MCP 配置执行静态扫描

mcp-scan auto-discovers known config locations; you can also pass a path explicitly.
bash
undefined
mcp-scan 会自动发现已知的配置位置;也可以显式传入路径。
bash
undefined

Scan all auto-discovered MCP configs

Scan all auto-discovered MCP configs

uvx mcp-scan@latest
uvx mcp-scan@latest

Scan a specific config file

Scan a specific config file

uvx mcp-scan@latest ~/.vscode/mcp.json
uvx mcp-scan@latest ~/.vscode/mcp.json

Emit machine-readable JSON for CI

Emit machine-readable JSON for CI

uvx mcp-scan@latest --json ~/.cursor/mcp.json > mcp_scan_report.json

mcp-scan flags tool poisoning, tool shadowing, cross-origin escalation, rug pulls, and toxic flows.
uvx mcp-scan@latest --json ~/.cursor/mcp.json > mcp_scan_report.json

mcp-scan 会标记工具投毒、工具遮蔽、跨源权限提升、rug pull 和有毒流程。

2. Inspect raw tool descriptions

2. 检查原始工具描述

Print every tool/prompt/resource description without verification, then read them for hidden instructions,
<important>
-style blocks, or imperative text aimed at the model.
bash
uvx mcp-scan@latest inspect ~/.cursor/mcp.json
Look for red flags: instructions to the assistant ("do not tell the user", "read ~/.ssh/id_rsa"), nested fake documentation, zero-width/Unicode-smuggled text, or directives to call other tools.
在不做验证的情况下打印每个工具/提示/资源描述,然后阅读这些描述,查找隐藏指令、
<important>
风格的区块,或针对模型发出的命令式文本。
bash
uvx mcp-scan@latest inspect ~/.cursor/mcp.json
需要警惕的危险信号包括:给助手的指令("do not tell the user"、"read ~/.ssh/id_rsa")、嵌套的伪造文档、零宽字符或利用 Unicode 字符夹带的文本,或要求调用其他工具的指令。

3. Pin tool hashes to detect rug pulls

3. 固定工具哈希以检测 rug pull

mcp-scan tracks tool description hashes so a later silent change is flagged. Run scans on a schedule; a hash mismatch on a previously approved tool indicates a rug pull.
bash
undefined
mcp-scan 会跟踪工具描述哈希,从而标记后续的静默变更。定期运行扫描;此前已批准工具出现哈希不匹配,即表示发生了 rug pull。
bash
undefined

Re-run regularly; mcp-scan reports changed tool hashes since last approval

Re-run regularly; mcp-scan reports changed tool hashes since last approval

uvx mcp-scan@latest ~/.cursor/mcp.json
undefined
uvx mcp-scan@latest ~/.cursor/mcp.json
undefined

4. Enumerate tools programmatically and audit metadata

4. 以编程方式枚举工具并审查元数据

Connect to the server with the official MCP SDK and inspect the advertised schema directly.
python
undefined
使用官方 MCP SDK 连接到服务器,并直接检查其公开的 schema。
python
undefined

enumerate_tools.py (stdio MCP server example)

enumerate_tools.py (stdio MCP server example)

import asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client
async def main(): params = StdioServerParameters(command="node", args=["./suspect-mcp-server.js"]) async with stdio_client(params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() tools = await session.list_tools() for t in tools.tools: print(f"{t.name}: {len(t.description or '')} chars") print((t.description or "")[:400])
asyncio.run(main())
undefined
import asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client
async def main(): params = StdioServerParameters(command="node", args=["./suspect-mcp-server.js"]) async with stdio_client(params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() tools = await session.list_tools() for t in tools.tools: print(f"{t.name}: {len(t.description or '')} chars") print((t.description or "")[:400])
asyncio.run(main())
undefined

5. Test URL-fetching tools for SSRF

5. 测试获取 URL 的工具是否存在 SSRF

If a tool accepts a URL and fetches it server-side, attempt to reach internal metadata/loopback targets (only on systems you own).
python
undefined
如果某个工具接受 URL 并在服务器端获取该 URL,请尝试访问内部元数据/回环目标(仅限您拥有的系统)。
python
undefined

ssrf_probe.py

ssrf_probe.py

import asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client
SSRF_TARGETS = [ "http://169.254.169.254/latest/meta-data/", # AWS IMDS "http://127.0.0.1:22/", "http://localhost:6379/", "file:///etc/passwd", ]
async def main(): params = StdioServerParameters(command="node", args=["./suspect-mcp-server.js"]) async with stdio_client(params) as (r, w): async with ClientSession(r, w) as s: await s.initialize() for url in SSRF_TARGETS: res = await s.call_tool("fetch_url", {"url": url}) body = str(res.content)[:200] print(f"[SSRF?] {url} -> {body}")
asyncio.run(main())
undefined
import asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client
SSRF_TARGETS = [ "http://169.254.169.254/latest/meta-data/", # AWS IMDS "http://127.0.0.1:22/", "http://localhost:6379/", "file:///etc/passwd", ]
async def main(): params = StdioServerParameters(command="node", args=["./suspect-mcp-server.js"]) async with stdio_client(params) as (r, w): async with ClientSession(r, w) as s: await s.initialize() for url in SSRF_TARGETS: res = await s.call_tool("fetch_url", {"url": url}) body = str(res.content)[:200] print(f"[SSRF?] {url} -> {body}")
asyncio.run(main())
undefined

6. Verify authentication and network exposure

6. 验证身份认证和网络暴露情况

Check that remote MCP servers (HTTP/SSE transport) require authentication and are not bound to
0.0.0.0
on untrusted networks.
bash
undefined
检查远程 MCP 服务器(HTTP/SSE transport)是否要求身份认证,并确保其未在不可信网络上绑定到
0.0.0.0
。
bash
undefined

Confirm whether an SSE/HTTP MCP endpoint responds without credentials

Confirm whether an SSE/HTTP MCP endpoint responds without credentials

curl -s -i http://mcp-host:8000/sse | head -n 20
curl -s -i http://mcp-host:8000/sse | head -n 20

Check listening interfaces of a locally running MCP server

Check listening interfaces of a locally running MCP server

ss -tlnp | grep -E ':(8000|3000|6277)'

An MCP endpoint that returns tool listings or accepts `tools/call` without auth is unauthenticated exposure — remediate with a token/OAuth and bind to localhost or an authenticated gateway.
ss -tlnp | grep -E ':(8000|3000|6277)'

如果 MCP 端点在无认证的情况下返回工具列表或接受 `tools/call`,则属于未认证暴露——请使用 token/OAuth 修复,并将其绑定到 localhost 或经过身份认证的 gateway。

7. Enforce runtime guardrails (optional)

7. 实施运行时护栏(可选)

For continuous protection, route agent MCP traffic through the mcp-scan proxy, which checks tool calls, data-flow constraints, PII, and indirect injection in real time.
bash
uvx --with "mcp-scan[proxy]" mcp-scan@latest proxy
若需持续保护,请将 Agent 的 MCP 流量路由到 mcp-scan proxy;该代理会实时检查工具调用、数据流约束、PII 和间接注入。
bash
uvx --with "mcp-scan[proxy]" mcp-scan@latest proxy

8. Report findings

8. 报告发现

Document each finding with server, tool, evidence (the poisoned description / SSRF response / unauth listing), severity, and ATLAS mapping. Recommend removing or sandboxing poisoned servers, adding auth, pinning approved tools, and enabling the proxy.
为每项发现记录对应服务器、工具、证据(被投毒的描述 / SSRF 响应 / 未认证工具列表)、严重性及 ATLAS 映射。建议移除或沙箱化被投毒的服务器、添加身份认证、固定已批准工具并启用 proxy。

Tools and Resources

工具与资源

ToolPurposeSource
mcp-scanStatic + runtime MCP security scannerhttps://github.com/invariantlabs-ai/mcp-scan
MCP Python SDKProgrammatic tool enumeration / callshttps://github.com/modelcontextprotocol/python-sdk
OWASP MCP Top 10MCP risk reference (MCP03 Tool Poisoning)https://owasp.org/www-project-mcp-top-10/
Invariant Labs blogTool poisoning disclosurehttps://invariantlabs.ai/blog/introducing-mcp-scan
MITRE ATLASAI threat technique taxonomyhttps://atlas.mitre.org/
工具用途来源
mcp-scan静态 + 运行时 MCP 安全扫描器https://github.com/invariantlabs-ai/mcp-scan
MCP Python SDK以编程方式枚举和调用工具https://github.com/modelcontextprotocol/python-sdk
OWASP MCP Top 10MCP 风险参考(MCP03 Tool Poisoning)https://owasp.org/www-project-mcp-top-10/
Invariant Labs blog工具投毒披露https://invariantlabs.ai/blog/introducing-mcp-scan
MITRE ATLASAI 威胁技术分类法https://atlas.mitre.org/

MCP Threat Reference

MCP 威胁参考

ThreatDescriptionDetection
Tool poisoningHidden instructions in tool descriptionmcp-scan scan / inspect
Tool shadowingMalicious server overrides trusted toolmcp-scan cross-origin checks
Rug pullDescription changes after approvalmcp-scan tool pinning (hash)
Toxic flowTool combo enabling exfiltrationmcp-scan toxic-flow analysis
SSRFURL-fetch tool reaches internal targetsssrf_probe against owned server
Unauth exposureMCP endpoint with no authcurl/ss interface and auth check
威胁描述检测方式
工具投毒工具描述中包含隐藏指令mcp-scan scan / inspect
工具遮蔽恶意服务器覆盖可信工具mcp-scan 跨源检查
Rug pull批准后描述发生变化mcp-scan 工具固定(哈希)
有毒流程可实现数据外传的工具组合mcp-scan toxic-flow 分析
SSRFURL 获取工具访问内部目标对自有服务器运行 ssrf_probe
未认证暴露无认证的 MCP 端点使用 curl/ss 检查接口和认证

Validation Criteria

验证标准

  • All installed MCP configs statically scanned with mcp-scan
  • Raw tool/prompt/resource descriptions inspected for hidden instructions
  • Tool hashes pinned and rug-pull detection enabled
  • Tools enumerated programmatically via the MCP SDK
  • URL-fetching tools tested for SSRF against owned targets
  • Authentication and network exposure of remote servers verified
  • Runtime proxy guardrails evaluated or deployed where appropriate
  • Findings mapped to MITRE ATLAS AML.T0010 and OWASP MCP03:2025
  • Severity assigned and remediation documented for each finding
  • Re-scan scheduled to catch future rug pulls
  • 已使用 mcp-scan 对所有已安装的 MCP 配置执行静态扫描
  • 已检查原始工具/提示/资源描述中的隐藏指令
  • 已固定工具哈希并启用 rug-pull 检测
  • 已通过 MCP SDK 以编程方式枚举工具
  • 已针对自有目标测试 URL 获取工具的 SSRF
  • 已验证远程服务器的身份认证和网络暴露情况
  • 已在适当位置评估或部署运行时 proxy 护栏
  • 已将发现映射到 MITRE ATLAS AML.T0010 和 OWASP MCP03:2025
  • 已为每项发现评定严重性并记录修复方案
  • 已安排重新扫描,以发现未来的 rug pull