akar5h/jakk
GitHub: akar5h/jakk
jakk 是一款不依赖 LLM 的 MCP 服务器黑盒安全扫描器,通过确定性探测在 CI 中快速发现命令注入、路径遍历、授权缺陷等漏洞。
Stars: 2 | Forks: 1
# jakk
**一款针对 MCP 服务器的黑盒安全扫描器。** 将其指向一个 MCP
endpoint;它将枚举服务器的工具,触发一系列精心挑选的
单次调用对抗性探测,并对返回的结果进行分类。无需在循环中使用 LLM
—— 具有确定性、速度快、零 token 成本。
[](https://github.com/akar5h/jakk/actions/workflows/ci.yml)
[](https://github.com/akar5h/jakk/actions/workflows/action-smoke.yml)
[](LICENSE)



[Model Context Protocol](https://modelcontextprotocol.io) 允许 LLM
代理调用外部服务器上的工具。这些服务器是一种全新的、快速增长的攻击面 —— 包括命令注入、路径遍历、
授权失效、SSRF、工具描述投毒。`jakk` 是
MCP 服务器维护者的快速第一道防线:只需添加一个 GitHub Action 步骤,
扫描你刚构建的服务器,并且仅在出现可重现的证据时才让 CI 失败。
```
$ jakk mcp scan --endpoint http://127.0.0.1:8008/mcp/stream --library library/mcp
──────────────── jakk scan :: http://127.0.0.1:8008/mcp/stream ────────────────
Probe results (13)
┏━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ outcome ┃ severity ┃ test id ┃ tool ┃ evidence ┃
┡━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━┩
│ vulnerable │ critical │ mcp.command.secret_… │ init_bare_repo… │ FLAG{git_co… │
│ vulnerable │ high │ mcp.command.shell_ma… │ init_bare_repo… │ …xJAKK-MARK… │
│ pass │ high │ mcp.schema.descripti… │ - │ │
│ ... │ │ │ │ │
└────────────┴──────────┴────────────────────────┴─────────────────┴──────────────┘
Tests run: 13 pass=4 skipped=5 vulnerable=4
4 vulnerability findings
```
## GitHub Action 快速入门
`jakk` 作为 CI 冒烟测试最为安全。该 Action 默认设置为 `safe: true`,
因此除非你明确选择进行更深入的测试,否则它只会运行只读 / 无副作用的探测。
本仓库在
[`.github/workflows/action-smoke.yml`](.github/workflows/action-smoke.yml) 中自测了该 Action:
CI 针对一个微型的 stdio MCP 服务器运行 `uses: ./`,验证是否写入了 JSONL,
并断言在干净的测试用例上没有触发任何发现结果。
对于已知的外部实现,请手动运行
[`真实目标冒烟测试`](.github/workflows/real-target-smoke.yml)。
它将以只读 HTTP 模式启动 GitHub 官方的 `github-mcp-server` Docker 镜像,使用本地 Action 对其进行扫描,
写入 JSONL + SARIF,使用 `github/codeql-action/upload-sarif@v3` 上传 SARIF,并保存发现结果的
artifact。
该工作流是真实目标 SARIF 摄取的冒烟测试。
公开的验证点:
- **GitHub 原生摄取:** PR #4 针对官方的 `github-mcp-server` 运行了 `真实目标冒烟测试`;
`upload-sarif` 验证了该 SARIF,将其上传,并且 GitHub 报告处理完成。
- **针对易受攻击目标的非空 SARIF:** 针对 `examples/external_targets/ch01-extended` 的本地运行
触发了 `mcp.authz.cross_tenant_read` 并被标记为 `critical`,生成了包含 `1` 条规则和 `1` 条结果的 SARIF 2.1.0。
这证明了相同的输出路径能够提供可操作的发现结果,而不仅仅是空的扫描元数据。
```
name: MCP security smoke test
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
security-events: write
jobs:
jakk:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Start your MCP server however your project normally does it.
- name: Start MCP server
run: |
./scripts/start-mcp-server.sh &
echo $! > /tmp/mcp-server.pid
- name: Wait for MCP endpoint
run: |
for i in {1..30}; do
curl -fsS http://127.0.0.1:8000/health && exit 0
sleep 1
done
exit 1
- name: Run jakk
uses: akar5h/jakk@v0.2
with:
endpoint: http://127.0.0.1:8000/mcp
args: "--bearer ${{ secrets.MCP_TEST_TOKEN }}"
sarif: jakk-findings.sarif
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: jakk-findings.sarif
- name: Upload findings
if: always()
uses: actions/upload-artifact@v4
with:
name: jakk-findings
path: jakk-findings.jsonl
```
对于允许发生数据变更的已授权测试目标,可以选择启用
完整的库:
```
- uses: akar5h/jakk@v0.2
with:
endpoint: http://127.0.0.1:8000/mcp
safe: "false"
args: "--bearer ${{ secrets.MCP_TEST_TOKEN }} --arg owner=octocat --arg repo=Hello-World"
```
## 安装
```
pip install jakk
# 或者,从源码:
git clone https://github.com/akar5h/jakk && cd jakk && pip install -e .
```
## 快速开始
```
# 使用只读 probe 扫描本地 MCP endpoint
jakk mcp scan --endpoint http://127.0.0.1:8008/mcp/stream --safe
# 一个经过身份验证的服务器,仅限安全(只读) probe,结果输出至 JSONL
jakk mcp scan \
--endpoint https://api.example.com/mcp/stream \
--bearer "$ACCESS_TOKEN" \
--safe \
--jsonl findings.jsonl \
--sarif findings.sarif
```
## 探测目录
涵盖 7 个攻击面的 13 个探测,覆盖了 OWASP-for-MCP 类别 MCP01–MCP05、MCP08 和 MCP10。
| 探测 | 类别 | 严重性 |
|---|---|---|
| `mcp.command.shell_marker` | 命令注入 (sink) | high |
| `mcp.command.secret_file_read` | 命令注入 (影响) | critical |
| `mcp.prefix_bypass` | CVE-2025-53110 startswith 绕过 | high |
| `mcp.path.canary_file_read` | 路径遍历 (影响) | critical |
| `mcp.response.secret_overshare` | 正常响应中的机密泄漏 | high |
| `mcp.response.directive_passthrough` | 通过响应进行的间接注入 | high |
| `mcp.schema.description_smuggling` | 通过描述进行的工具投毒 | high |
| `mcp.auth.no_credential` | 接受匿名访问 | critical |
| `mcp.auth.invalid_token` | 接受无效 token | critical |
| `mcp.auth.wrong_prefix` | 在没有 scheme 的情况下接受 bearer | low |
| `mcp.authz.cross_tenant_read` | 迷惑代理 / BOLA | critical |
| `mcp.ssrf.cloud_metadata` | 针对云元数据 endpoint 的 SSRF | critical |
| `mcp.sql.error_based` | 通过 query 型参数进行的 SQL 注入 | high |
[`docs/tests/`](docs/tests/) 中有针对每个探测的详细说明。对于攻击者而言,每个 `vulnerable`
判定结果的具体含义详见:[`docs/threat-models.md`](docs/threat-models.md)。
## 结果
每个探测都会产生六种结果中的一种 —— 只有 `vulnerable` 需要进行分类筛查:
| 结果 | 含义 |
|---|---|
| **vulnerable** | 响应表明服务器偏离了其应保持的安全属性。 |
| **echo** | 输入被反射但未被解析 —— 其本身不可被利用。 |
| **suggestive** | 不同调用之间的验证结果不一致;重新运行以明确判断。 |
| **pass** | 探测已运行,响应干净(包括服务器安全地拒绝了该输入)。 |
| **skipped** | 没有兼容的工具,或缺少配置(`--arg`、`--bearer`)。这不算失败。 |
| **error** | 无法完成调用(传输失败)。 |
`jakk` 能够区分*"服务器拒绝了我们的恶意输入"* (pass)
和*"我们无法进行测试"* (error),以及*"发生了 shell 展开"*
(vulnerable) 和*"输入被原样回显"* (echo)。一个误报频发的扫描器比没有扫描器更糟糕 —— 每一次 `vulnerable` 都应是真实的。
## 它有何不同
- **无需 LLM。** 匹配器是确定性的(正则表达式 / canary 回显 / schema 扫描)。零 token 成本,完全可复现。
- **GitHub 原生。** 该 Action 默认安全,输出 JSONL + SARIF,并且可以通过 `--exit-nonzero-on-fired` 在出现 `vulnerable` 发现结果时阻止 PR 合并。
- **Schema 感知,与供应商无关。** 探测通过*语义角色*(`path`、`url`、`query` 等)来定位参数,因此无论服务器如何命名其参数,同一个库可以适用于各种服务器。([详情](docs/context-args/README.md))
- **诚实的分类。** 6 种结果的分类法,将真实的发现结果与输入反射以及“无法测试”的情况区分开来。
- **它自己也在使用自身。** `jakk` 自身的攻击面已经过审计 —— 参见 [`docs/2026-05-23_self-security-audit.md`](docs/2026-05-23_self-security-audit.md)。
`jakk` 是 MCP 安全测试的*服务器端*部分。而
*代理端*部分(多轮次、针对使用 MCP 的代理进行 LLM 自适应攻击)则是另一个不同的问题,需要使用单独的工具。
## 在故意设计的易受攻击的实验环境中尝试
```
# 获取 breach-to-fix 实验靶标(含 vulnerable 和 hardened 变体)
./examples/external_targets/fetch.sh
docker compose -f examples/external_targets/_vendor/mcp-breach-to-fix-labs/docker-compose.yml \
up -d git-command-injection-vulnerable git-command-injection-secure
jakk mcp scan --endpoint http://127.0.0.1:8008/mcp/stream --library library/mcp # fires
jakk mcp scan --endpoint http://127.0.0.1:9008/mcp/stream --library library/mcp # clean
```
为了得到简洁的阳性 SARIF 证据,请运行本地的 ch01 authz 实验:
```
CHALLENGE_HOST=127.0.0.1 CHALLENGE_PORT=18011 \
CH01_EXT_DATA_PATH=/path/to/projects.json \
python examples/external_targets/ch01-extended/server.py
jakk mcp scan \
--endpoint http://127.0.0.1:18011/mcp/stream \
--library library/mcp \
--select mcp.authz.cross_tenant_read \
--cred-a alpha-api-key \
--cred-b bravo-api-key \
--foreign-id CRM-1001 \
--jsonl ch01-extended.jsonl \
--sarif ch01-extended.sarif
```
预期数据点:`vulnerable=1`,SARIF `results.length == 1`,规则
`mcp.authz.cross_tenant_read`。
目标列表请参见 [`examples/external_targets/`](examples/external_targets/),关于 ch01 / ch02 / ch08 的实时结果
请参见 [`docs/2026-05-22_smoke-report.md`](docs/2026-05-22_smoke-report.md)。
## 负责任地使用
`jakk` 是一款进攻性安全工具。仅在你拥有或获得明确授权进行测试的系统(你自己的基础设施、漏洞赏金计划的明确范围或付费的测试委托)上运行它。
[深度暴露方法](docs/depth-of-exposure-methodology.md)
记录了在接触任何你不拥有的目标之前应进行的授权预检。报告安全问题请遵循 [SECURITY.md](SECURITY.md)。
## License
[Apache 2.0](LICENSE)。
标签:DOE合作, MCP服务器, Python, XXE攻击, 图数据库, 无后门, 请求拦截, 逆向工具, 黑盒测试