审计MCP服务器的工具投毒风险 是做什么的?
仅限授权使用说明: 审计MCP服务器会连接并探测在线工具端点。请只扫描你拥有或获得评估授权的服务器。将扫描到的工具描述视为不可信输入——不要将未审计的MCP服务器加载到特权代理中。未经许可探测第三方MCP端点的SSRF或认证弱点可能构成非法行为。
概述
模型上下文协议(MCP)允许AI代理发现并调用由MCP服务器公布的外部工具。每个工具都暴露一个名称和一段自然语言的描述,代理的LLM在决定调用该工具之前会读取这段描述。2025年初,Invariant Labs披露这个描述字段是一个攻击面:恶意服务器可以在工具描述中嵌入隐藏指令(工具投毒攻击,OWASP MCP03:2025),而能力较强的模型会静默执行这些指令——窃取文件、泄露密钥或将工具调用重定向——同时向用户返回一个看似正常的响应。由于工具描述会被加载到代理的上下文中,工具投毒本质上是通过供应链实施的间接提示注入(MITRE ATLAS AML.T0010 ML供应链攻陷)。
除了投毒之外,MCP服务器还引入了经典的基础设施风险:工具影子攻击(恶意服务器覆盖可信工具的行为)、撤单攻击(工具描述在用户批准后发生变化)、毒性流程(多个工具组合导致数据泄露)、工具中获取URL的SSRF,以及绑定到网络接口的MCP服务器的未认证暴露。本技能使用Invariant Labs的mcp-scan对MCP服务器进行端到端的静态和运行时分析审计,同时辅以SSRF和认证的手动检查,并通过工具哈希锁定来检测撤单攻击。
何时使用
- 在向代理栈(Claude Desktop、Cursor、VS Code、Windsurf、自定义代理)添加新的MCP服务器之前。
- 在内部开发的MCP服务器进行安全审查时。
- 在验证已批准的工具是否未发生静默变化时(撤单攻击检测)。
- 作为CI/CD流水线关卡,在每次变更时扫描MCP配置和SKILL/工具定义。
- 在事件响应过程中,当代理执行了与被毒化工具行为一致的非预期操作时。
前提条件
- Python 3.10+ 和
uv(用于uvx),或 pip。 - 要扫描的MCP配置文件(例如
~/.cursor/mcp.json、~/.vscode/mcp.json、Claude Desktop 配置)。 - 安装工具:
# uv 提供了 uvx(mcp-scan 的推荐运行器)
curl -LsSf https://astral.sh/uv/install.sh | sh # 或:pipx install uv
# mcp-scan(Invariant Labs)——使用 uvx 无需全局安装
uvx mcp-scan@latest --help
# 运行时代理模式(需要额外的扩展包)
uvx --with "mcp-scan[proxy]" mcp-scan@latest proxy --help
# 手动探测辅助工具
pip install requests mcp
目标
- 对所有已安装的MCP服务器进行静态扫描,检测工具投毒、影子攻击、撤单攻击和毒性流程。
- 检查原始工具/提示/资源描述中是否存在隐藏或混淆的指令。
- 锁定工具哈希以检测批准后的描述变更(撤单攻击防御)。
- 测试获取URL的工具是否存在服务器端请求伪造(SSRF)。
- 验证MCP服务器是否经过认证,以及是否未暴露在不受信任的接口上。
- (可选)通过 mcp-scan 代理强制实施运行时防护措施。
MITRE ATT&CK 映射
| ID | 官方名称 | 相关性 |
|---|---|---|
| AML.T0010 | ML供应链攻陷 | 被毒化的第三方MCP服务器是对代理的供应链攻陷 |
| AML.T0051.001 | LLM提示注入:间接 | 被毒化的工具描述是对代理上下文的间接注入 |
| AML.T0053 | LLM插件攻陷 | MCP工具是代理的插件;投毒即攻陷了插件 |
| AML.T0057 | LLM数据泄露 | 被毒化工具的常见载荷:窃取文件/密钥 |
工作流程
1. 已安装MCP配置的静态扫描
mcp-scan 会自动发现已知的配置位置;你也可以显式传递路径。
# 扫描所有自动发现的MCP配置
uvx mcp-scan@latest
# 扫描特定的配置文件
uvx mcp-scan@latest ~/.vscode/mcp.json
# 输出机器可读的JSON用于CI
uvx mcp-scan@latest --json ~/.cursor/mcp.json > mcp_scan_report.json
mcp-scan 会标记出工具投毒、工具影子攻击、跨源升级、撤单攻击和毒性流程。
2. 检查原始工具描述
打印每个工具/提示/资源描述(不进行验证),然后手动检查其中是否存在隐藏指令、<important>风格块或面向模型的命令性文本。
uvx mcp-scan@latest inspect ~/.cursor/mcp.json
寻找危险信号:对助手的指令(“不要告诉用户”、“读取 ~/.ssh/id_rsa”)、内嵌的虚假文档、零宽/Unicode走私文本,或指示调用其他工具的指令。
3. 锁定工具哈希以检测撤单攻击
mcp-scan 会追踪工具描述的哈希值,以便在后续静默变更时发出警报。定期运行扫描;之前已批准的工具出现哈希不匹配则表明发生了撤单攻击。
# 定期重新运行;mcp-scan 会报告自上次批准以来变更的工具哈希
uvx mcp-scan@latest ~/.cursor/mcp.json
4. 编程枚举工具并审计元数据
使用官方MCP SDK连接服务器,直接检查公布的架构。
# enumerate_tools.py(stdio MCP服务器示例)
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 '')} 字符")
print((t.description or "")[:400])
asyncio.run(main())
5. 测试获取URL的工具是否存在SSRF
如果某个工具接受URL并在服务器端获取它,请尝试访问内部元数据/回环目标(仅在你拥有的系统上操作)。
# 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())
6. 验证认证和网络暴露
检查远程MCP服务器(HTTP/SSE传输)是否需要认证,以及是否绑定到不受信任网络上的 0.0.0.0。
# 确认SSE/HTTP MCP端点在无凭据情况下是否响应
curl -s -i http://mcp-host:8000/sse | head -n 20
# 检查本地运行MCP服务器的监听接口
ss -tlnp | grep -E ':(8000|3000|6277)'
如果某个MCP端点无需认证即可返回工具列表或接受 tools/call 调用,则属于未认证暴露——应通过令牌/OAuth进行修复,并绑定到本地主机或经过认证的网关。
7. 实施运行时防护措施(可选)
为了持续保护,可以将代理的MCP流量路由经过 mcp-scan 代理,该代理会实时检查工具调用、数据流约束、PII和间接注入。
uvx --with "mcp-scan[proxy]" mcp-scan@latest proxy
8. 报告发现
记录每个发现,包括服务器、工具、证据(被毒化的描述/SSRF响应/未认证的列表)、严重等级和ATLAS映射。建议删除或隔离被毒化的服务器,添加认证,锁定已批准的工具,并启用代理。
工具与资源
| 工具 | 用途 | 来源 |
|---|---|---|
| mcp-scan | MCP安全静态+运行时扫描器 | https://github.com/invariantlabs-ai/mcp-scan |
| MCP Python SDK | 程序化工具枚举/调用 | https://github.com/modelcontextprotocol/python-sdk |
| OWASP MCP Top 10 | MCP风险参考(MCP03:工具投毒) | https://owasp.org/www-project-mcp-top-10/ |
| Invariant Labs博客 | 工具投毒披露 | https://invariantlabs.ai/blog/introducing-mcp-scan |
| MITRE ATLAS | AI威胁技术分类 | https://atlas.mitre.org/ |
MCP威胁参考
| 威胁 | 描述 | 检测方法 |
|---|---|---|
| 工具投毒 | 工具描述中的隐藏指令 | mcp-scan 扫描/检查 |
| 工具影子攻击 | 恶意服务器覆盖可信工具 | mcp-scan 跨源检查 |
| 撤单攻击 | 批准后描述变更 | mcp-scan 工具锁定(哈希) |
| 毒性流程 | 工具组合导致数据泄露 | mcp-scan 毒性流程分析 |
| SSRF | 获取URL的工具访问内部目标 | 针对自有服务器的 ssrf_probe |
| 未认证暴露 | 无认证的MCP端点 | curl/ss 接口与认证检查 |
验证标准
- 所有已安装的MCP配置已通过 mcp-scan 进行静态扫描
- 已检查原始工具/提示/资源描述中是否存在隐藏指令
- 工具哈希已锁定,撤单攻击检测已启用
- 已通过MCP SDK程序化枚举工具
- 已针对自有目标测试了获取URL的工具是否存在SSRF
- 已验证远程服务器的认证和网络暴露情况
- 已评估运行时代理防护措施,并在适当场景下部署
- 发现项已映射到MITRE ATLAS AML.T0010和OWASP MCP03:2025
- 每个发现项均已分配严重等级并记录了修复方案
- 已安排重新扫描以捕获未来的撤单攻击