bogdanticu88/mcp-map
GitHub: bogdanticu88/mcp-map
针对 MCP 服务器和 LLM 工具定义的静态攻击面分析器,帮助用户在安装前发现配置中潜藏的权限过大、凭证泄露、供应链投毒等安全风险。
Stars: 0 | Forks: 0
mcpmap
针对 MCP 服务器和 LLM 工具定义的静态攻击面分析器。
## 为什么这很重要
MCP 服务器以启动它的用户所拥有的相同 OS 权限运行。当你将服务器添加到 Claude Desktop 配置中时,你正在授予它读取文件、执行命令、调用 API 和发送电子邮件的能力——在每次会话启动时静默进行。
大多数人安装 MCP 服务器的方式与安装浏览器扩展相同:非常快速,而不检查它们的功能。不同之处在于,MCP 服务器在你的 AI 代理的上下文中运行,这意味着单个恶意或配置错误的服务器可以:
- 通过 prompt injection 在你的机器上**执行 shell 命令**
- 从广泛的文件系统路径中**读取 SSH 密钥、token 和凭证**
- 通过由恶意 prompt 触发的电子邮件或 HTTP 工具**窃取数据**
- **跨会话持久存在**,因为配置是自动加载的
mcpmap 会在上述任何情况发生之前扫描你的配置。它只需不到一秒钟的时间,不需要网络访问权限,并将每个发现映射到 [OWASP LLM Top 10](https://genai.owasp.org/) 和 [MITRE ATLAS](https://atlas.mitre.org/),以便你确切了解每个问题会引发哪类攻击。
## 功能特性
- 跨 CRITICAL / HIGH / MEDIUM / LOW 严重级别的 24 条检测规则
- 支持 Claude Desktop `claude_desktop_config.json`、MCP 配置格式、OpenAI 工具定义以及远程 HTTP/SSE MCP 服务器
- **基于信息熵的机密检测**:即使在环境变量名称看起来不像密钥时,也能捕获硬编码的机密信息
- **未固定版本包检测**:标记没有版本固定的 `npx -y @pkg/name`
- **Typosquatting(抢注)检测**:与受信任发布者进行编辑距离比对
- **对抗性指令检测**:标记嵌入在工具描述中的 prompt injection 模式
- 通过 `.mcpmap-ignore` 实现**抑制 / 允许列表**:静默已知发现而不丢失其他覆盖范围
- **基线 / 差异模式**:`--baseline` 仅显示自上次扫描以来的更改
- **上下文感知的修复建议**:建议会指出需要修复的确切路径、密钥或包
- 输出格式:Markdown、JSON、HTML(暗色模式报告)、SARIF(用于 GitHub Code Scanning)
- REST API (`mcpmap serve`) 用于与 Web 工具集成
- 用于 CI 门禁强制执行的 `--fail-on` 标志
- 通过 `--rules` 标志支持自定义规则
## 安装
```
pip install mcpmap
```
或从源码安装:
```
git clone https://github.com/bogdanticu88/mcp-map
cd mcp-map
pip install -e ".[dev]"
```
适用于 Windows、macOS 和 Linux。要求 Python 3.9+。
设置 `NO_COLOR=1` 以禁用所有彩色输出。
## 快速开始
```
# 找到你的 Claude Desktop config(跨平台)
mcpmap find
# 扫描 config 文件
mcpmap scan ~/.config/Claude/claude_desktop_config.json
# 扫描目录中的所有 JSON/YAML config
mcpmap scan ./configs/
# 显示所有内置检测规则
mcpmap rules
# 输出 HTML 报告
mcpmap scan config.json --format html --output report.html
# 如果检测到任何 HIGH 或 CRITICAL 发现则使 CI 失败
mcpmap scan config.json --fail-on HIGH
# 仅显示自上次扫描以来的新发现
mcpmap scan config.json --save-baseline baseline.json
mcpmap scan config.json --baseline baseline.json
```
## Claude Desktop 配置位置
| OS | 默认路径 |
|---|---|
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
| Linux | `~/.config/Claude/claude_desktop_config.json` (或 `$XDG_CONFIG_HOME/Claude/`) |
运行 `mcpmap find` 以检查当前系统上的所有已知路径。
## CLI 参考
```
mcpmap [OPTIONS] COMMAND [ARGS]...
```
### `mcpmap scan`
```
mcpmap scan [OPTIONS] TARGETS...
```
TARGETS 可以是单个文件或目录。目录会递归遍历以查找 `.json`、`.yaml` 和 `.yml` 文件。
| 选项 | 描述 |
|---|---|
| `--format`, `-f` | 输出格式:`markdown` (默认), `json`, `html`, `sarif` |
| `--output`, `-o` | 将报告写入文件而不是 stdout |
| `--fail-on` | 如果有任何发现达到或超过此严重级别则退出并返回代码 1 (`CRITICAL`, `HIGH`, `MEDIUM`, `LOW`) |
| `--summary` | 仅打印终端汇总表 |
| `--ascii` | 仅 ASCII 输出(无 emoji/徽章) |
| `--rules` | 自定义规则 YAML 的路径;替换内置规则集 |
| `--ignore-file` | 抑制文件的路径(默认:目标目录或 CWD 中的 `.mcpmap-ignore`) |
| `--no-ignore` | 禁用所有抑制文件加载 |
| `--show-suppressed` | 在报告中包含被抑制的发现 |
| `--baseline` | 先前 JSON 扫描结果的路径;将新发现标记为 NEW |
| `--save-baseline` | 将当前结果保存为基线 JSON 文件 |
| `--version`, `-V` | 显示版本并退出 |
### 退出代码
| 代码 | 含义 |
|---|---|
| `0` | 没有发现达到或超过 `--fail-on` 阈值(或未设置 `--fail-on`) |
| `1` | 有一个或多个发现达到或超过 `--fail-on` 严重级别阈值 |
| `2` | 无效的 `--rules` 或 `--baseline` 路径、未找到目标或输出文件不可写 |
### `mcpmap rules`
```
mcpmap rules [--rules PATH]
```
以表格形式列出所有检测规则(ID、严重级别、类别、名称)。传递 `--rules` 以在用于扫描之前预览自定义规则文件。
### `mcpmap find`
```
mcpmap find
```
检测你的 OS 并列出已知的 Claude Desktop 配置位置,指示哪些存在。为找到的文件输出一个可直接粘贴的 `mcpmap scan` 命令。
### `mcpmap serve`
```
mcpmap serve [OPTIONS]
```
| 选项 | 描述 |
|---|---|
| `--host` | 绑定主机 (默认: `127.0.0.1`) |
| `--port`, `-p` | 绑定端口, 1-65535 (默认: `8000`) |
| `--rules` | 自定义规则 YAML 的路径 |
## 抑制 / 允许列表
在你的项目根目录或配置文件旁边创建一个 `.mcpmap-ignore` 文件:
```
# 在任何地方抑制此规则
MCM-014
# 仅针对命名 server 进行抑制
MCM-010:my-internal-server
# 抑制你已审计过的 server 的所有发现
*:legacy-mcp-server
```
每行格式:`RULE_ID` 或 `RULE_ID:server_name` 或 `*:server_name`。以 `#` 开头的行是注释。
mcpmap 会在第一个扫描目标旁边查找 `.mcpmap-ignore`,然后在当前工作目录中查找。使用 `--ignore-file PATH` 覆盖或使用 `--no-ignore` 完全禁用。
```
# 使用自定义抑制文件进行扫描
mcpmap scan config.json --ignore-file security/approved.ignore
# 将抑制的发现与活动的发现一同显示
mcpmap scan config.json --show-suppressed
```
## 基线 / 差异模式
跟踪两次扫描之间的变化。在 CI 中用于仅在出现回退时发出警报。
```
# 步骤 1:将当前发现保存为 baseline
mcpmap scan config.json --save-baseline baseline.json
# 步骤 2(稍后,在 CI 中):与之进行对比
mcpmap scan config.json --baseline baseline.json
```
输出中的每个发现都会被标记为:
- **NEW**:该发现在基线中不存在
- **Resolved**:该发现在基线中存在但现已不再被检测到
- **Unchanged**:在两者中都存在(在差异摘要中隐藏)
与 `--fail-on` 结合使用,以仅在引入新发现时使 CI 失败:
```
mcpmap scan config.json --baseline baseline.json --fail-on HIGH
```
## REST API
启动服务器:
```
mcpmap serve
```
### `POST /analyze`
分析配置 payload。
```
curl -s http://localhost:8000/analyze \
-H "Content-Type: application/json" \
-d '{
"content": {
"mcpServers": {
"bash": {
"command": "npx",
"args": ["-y", "@anthropic-ai/mcp-server-bash"],
"env": {"API_KEY": "sk-..."}
}
}
},
"filename": "config.json",
"format": "json"
}'
```
**请求字段:**
| 字段 | 类型 | 描述 |
|---|---|---|
| `content` | object | 要分析的配置 |
| `filename` | string | 格式检测的提示 (默认: `config.json`) |
| `format` | string | `report` 字段中的报告格式: `json`, `markdown`, `html`, `sarif` |
| `fail_on` | string | 可选的严重级别阈值;在响应中设置 `failed: true` |
**响应:**
```
{
"results": [...],
"summary": {"CRITICAL": 2, "HIGH": 1, "MEDIUM": 0, "LOW": 0, "TOTAL": 3},
"failed": true,
"report": "..."
}
```
### `GET /rules`
列出所有已加载的规则及其严重级别、类别和框架映射。
### `GET /health`
返回 `{"status": "ok", "version": "..."}`.
## 支持的输入格式
### MCP 配置 (`claude_desktop_config.json`)
基于本地进程的服务器:
```
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem@1.2.3", "/home/user/projects"],
"env": {}
}
}
}
```
远程 HTTP/SSE 服务器(也会被扫描):
```
{
"mcpServers": {
"remote-assistant": {
"url": "https://mcp.example.com/sse",
"headers": {"Authorization": "Bearer sk-..."}
}
}
}
```
### OpenAI 工具定义
```
{
"tools": [
{
"type": "function",
"function": {
"name": "run_bash",
"description": "Execute a bash command",
"parameters": {
"type": "object",
"properties": {"command": {"type": "string"}}
}
}
}
]
}
```
## 规则集
### CRITICAL
| ID | 名称 | 类别 |
|---|---|---|
| MCM-001 | Shell / 命令执行能力 | Excessive Agency |
| MCM-002 | 任意代码执行能力 | Excessive Agency |
| MCM-003 | 凭证和机密存储访问 | Sensitive Data Exposure |
| MCM-004 | 进程管理能力 | Excessive Agency |
### HIGH
| ID | 名称 | 类别 |
|---|---|---|
| MCM-005 | 文件系统写入访问权限 | Excessive Agency |
| MCM-006 | 不受限制的网络获取 / HTTP 请求 | Data Exfiltration |
| MCM-007 | 电子邮件发送能力 | Data Exfiltration |
| MCM-008 | Git 写入 / 仓库推送访问权限 | Supply Chain |
| MCM-009 | 数据库写入 / 删除访问权限 | Excessive Agency |
| MCM-010 | 服务器环境中暴露的 API 密钥或 Token | Sensitive Data Exposure |
| MCM-011 | 广泛的文件系统访问权限 (根目录或主目录) | Sensitive Data Exposure |
| MCM-012 | 权限过高的 MCP 服务器 | Excessive Agency |
| MCM-020 | 自动接受运行器中未固定版本的包 | Supply Chain |
| MCM-021 | 工具描述中嵌入的对抗性指令 | Prompt Injection Risk |
| MCM-022 | 服务器环境中的高熵机密 | Sensitive Data Exposure |
| MCM-024 | 类似受信任发布者的包名 (Typosquatting) | Supply Chain |
### MEDIUM
| ID | 名称 | 类别 |
|---|---|---|
| MCM-013 | 不受限制的 Web 浏览 / 浏览器自动化 | Prompt Injection Risk |
| MCM-014 | 未经验证的第三方 MCP 服务器 | Supply Chain |
| MCM-015 | 工具缺少描述 (工具混淆风险) | Tool Confusion |
| MCM-016 | 敏感目录读取访问权限 | Sensitive Data Exposure |
| MCM-023 | 通过 HTTP/SSE 的远程 MCP 服务器 | Supply Chain |
### LOW
| ID | 名称 | 类别 |
|---|---|---|
| MCM-017 | 日历写入访问权限 | Data Exfiltration |
| MCM-018 | 社交媒体发布能力 | Data Exfiltration |
| MCM-019 | 推送通知发送能力 | Data Exfiltration |
每个发现包括:
- OWASP LLM Top 10 参考
- MITRE ATLAS 技术参考
- 上下文感知的修复指南(指出需要修复的确切路径、密钥或包)
- 证据字符串(匹配的内容及位置)
### 检测技术
| 规则 | 检测方法 |
|---|---|
| MCM-001 到 MCM-019 | 基于服务器名称、包名、工具名称、描述、环境变量键和文件系统路径的模式匹配 |
| MCM-020 | 检测带有 `-y`/`--yes` 且没有版本固定包参数的 `npx`/`uvx`/`bunx` |
| MCM-021 | 匹配工具描述中 20+ 个已知的 prompt injection 短语模式 |
| MCM-022 | 对长度 >= 20 个字符的环境变量值检测 Shannon 熵 >= 4.5 比特/字符(排除 URL/路径) |
| MCM-023 | 检测使用 `url` 字段而不是本地 `command` 配置的服务器 |
| MCM-024 | 包作用域与受信任发布者名称之间的 Levenshtein 距离 <= 2 |
## 自定义规则
使用你自己的 YAML 文件扩展或替换内置规则:
```
rules:
- id: CUSTOM-001
name: My Custom Rule
description: Detects a dangerous pattern specific to our environment.
severity: HIGH
category: Excessive Agency
owasp_llm:
- id: LLM06
name: "Excessive Agency"
url: "https://genai.owasp.org/llmrisk/llm06-excessive-agency/"
mitre_atlas:
- id: AML.T0051.001
name: "LLM Prompt Injection: Indirect"
url: "https://atlas.mitre.org/techniques/AML.T0051.001"
remediation: Remove or gate this tool behind human confirmation.
detection:
tool_name_patterns:
- my_dangerous_tool
tool_description_keywords:
- dangerous operation
```
```
mcpmap scan config.json --rules my_rules.yaml
# 预览将加载哪些规则
mcpmap rules --rules my_rules.yaml
```
### 检测字段
| 字段 | 类型 | 描述 |
|---|---|---|
| `server_name_patterns` | list[str] | 服务器名称的子字符串匹配 |
| `package_patterns` | list[str] | 包名称的子字符串匹配 |
| `broad_path_patterns` | list[str] | 对参数的精确或子目录前缀匹配 |
| `sensitive_path_patterns` | list[str] | 对参数的子字符串匹配 |
| `env_key_patterns` | list[str] | 环境变量键的子字符串匹配 |
| `env_value_entropy_threshold` | float | 标记 Shannon 熵高于此级别的环境变量值 |
| `env_value_min_length` | int | 熵检查的最小值长度默认: 20) |
| `tool_name_patterns` | list[str] | 工具名称的子字符串匹配 |
| `tool_description_keywords` | list[str] | 工具描述的子字符串匹配 |
| `description_injection_patterns` | list[str] | 在工具描述中检测的对抗性短语 |
| `parameter_names` | list[str] | 工具参数名称的子字符串匹配 |
| `check_empty_description` | bool | 标记没有描述的工具 |
| `check_unpinned_package` | bool | 标记没有版本固定的自动接受运行器 |
| `check_remote_server` | bool | 标记使用 `url` 字段配置的服务器 |
| `check_typosquatting` | bool | 启用针对受信任发布者的编辑距离检查 |
| `typosquatting_distance` | int | 触发标记的最大编辑距离 (默认: 2) |
| `trusted_package_prefixes` | list[str] | 用于供应链检查的受信任发布者前缀 |
| `high_risk_tool_threshold` | int | 触发 MCM-012 的高风险发现数量 |
## CI/CD 集成
### GitHub Actions
```
- name: Scan MCP config
run: |
pip install mcpmap
mcpmap scan claude_desktop_config.json --fail-on HIGH --format sarif --output mcpmap.sarif
- name: Upload SARIF to Code Scanning
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: mcpmap.sarif
```
通过基线差异仅在出现新的回退时失败:
```
- name: Restore baseline
uses: actions/cache@v4
with:
path: mcpmap-baseline.json
key: mcpmap-baseline-${{ github.base_ref }}
- name: Scan MCP config
run: |
pip install mcpmap
mcpmap scan config.json \
--baseline mcpmap-baseline.json \
--save-baseline mcpmap-baseline.json \
--fail-on HIGH
- name: Save updated baseline
uses: actions/cache@v4
with:
path: mcpmap-baseline.json
key: mcpmap-baseline-${{ github.ref_name }}
```
### Pre-commit Hook
```
repos:
- repo: local
hooks:
- id: mcpmap
name: mcpmap MCP security scan
entry: mcpmap scan
args: ["--fail-on", "CRITICAL"]
language: python
files: "claude_desktop_config\\.json|mcp.*\\.json"
```
## Docker
```
docker build -t mcpmap .
docker run --rm -v $(pwd):/work mcpmap scan /work/config.json
```
## 开发
```
pip install -e ".[dev]"
pytest
ruff check mcpmap/
```
你也可以将 CLI 作为模块调用:
```
python -m mcpmap scan config.json
python -m mcpmap find
python -m mcpmap rules
```
## 安全框架映射
mcpmap 的发现映射到:
- **[OWASP LLM Top 10](https://genai.owasp.org/)**: LLM01 Prompt Injection, LLM02 Sensitive Information Disclosure, LLM03 Supply Chain, LLM06 Excessive Agency
- **[MITRE ATLAS](https://atlas.mitre.org/)**: AML.T0051.000 (Direct Prompt Injection), AML.T0051.001 (Indirect Prompt Injection), AML.T0054 (LLM Jailbreak), AML.T0048 (Societal Harm)
## 局限性
mcpmap 是一个静态分析器。它读取配置文件而不执行任何代码或发出网络请求。
- 它无法检测运行时配置错误或在代理启动后引入的漏洞。
- 基于熵的机密检测 (MCM-022) 可能会在看起来随机的长值(例如,base64 编码的证书、连接的 UUID)上产生误报。使用 `.mcpmap-ignore` 来抑制已确认的非机密项。
- Typosquatting 检测 (MCM-024) 将包作用域与内置的受信任发布者列表进行比较。不在该列表中的发布者将不被检查。
- 模式匹配规则 (MCM-001 到 MCM-019) 会寻找已知危险的名称和功能。封装了危险操作但具有自定义名称的新工具不会被检测到,除非它们匹配已知模式或自定义规则。
- mcpmap 不执行沙箱执行、导入分析或动态污点分析。
## 许可证
MIT。详情请见 [许可证](LICENSE)。
标签:AI Agent安全, CISA项目, DLL 劫持, LLM工具, MCP服务器, PyPI, Python, Redis利用, SAST, Shell执行, 云安全监控, 人工智能安全, 凭证读取, 合规性, 大语言模型, 安全扫描, 恶意插件检测, 提示注入, 攻击面分析, 文档安全, 文档结构分析, 无后门, 时序注入, 盲注攻击, 系统权限, 网络安全, 网络安全审计, 网络测绘, 请求拦截, 逆向工具, 配置审查, 隐私保护, 集群管理, 静态分析