Skip to main content
Glama

mcp-vulbox-agent

面向合法授权众测、自有资产、靶场或明确书面授权测试的「人工主导、AI 辅助」安全测试工作台。 不是自动化挖洞机器人,不是无人值守扫描器,不是自动提交系统。

Agent 通过 MCP Server 调用一组合规、非破坏性、可审计的工具,完成项目接入 → 范围读取 → 资产发现 → 非破坏性安全验证 → 证据收集 → 报告草稿生成 → 人工提交跟踪。

项目定位声明是硬编码常量 PROJECT_POSITIONING(见 src/mcp_vulbox_agent/__init__.py), CLI version 子命令与 MCP Server 启动日志都会原样打印它——它不是文档里的形容词,是代码里的字符串。


⚠️ 这不是什么

请先读这一段,再决定要不要继续。

它不是

依据

不是自动化挖洞机器人

没有扫描调度器,没有资产遍历循环。每一个出网动作都由 Agent 单次调用触发,且必须携带一次性人工确认令牌。

不是无人值守扫描器

主动工具默认全关,需要在 config/config.yaml 与环境变量同时列入白名单才会被启用;MCP_VULBOX_ACTIVE_TOOLS 留空 = 全部关闭。没有定时任务、没有批量目标参数。

没有自动提交能力

适配层基类的 submit_report 永远抛错(src/mcp_vulbox_agent/vulbox/base.py),report.auto_submit 被硬约束禁止开启。report_mark_submitted 是回填工具:要求草稿已通过人工复核,且它不发起任何平台请求。

不是绕过平台风控的工具

vulbox.bypass_platform_controls 禁止开启;live 适配器只发 GET、不重试 4xx、不模拟浏览器登录态。

不提供自定义注入载荷

高风险工具只接受 config/safe_checks.yaml 中登记的 check_id,自定义载荷一律 PAYLOAD_NOT_ALLOWED。

资源层不是第二条能力通道

MCP 资源只暴露 Agent 本来就能通过被动工具拿到的数据(vulbox://scope 就是经 auth_list 取的),技能文档是仓库里的静态文件。任何需要出网、需要人工确认或含密钥的内容都不做成资源——那等于给管线的约束开旁路。

如果你要找的是「输入域名 → 自动出报告」,这个项目帮不上忙,而且它存在的意义恰恰是拒绝这种用法。


Related MCP server: apex

为什么需要它

AI 在安全测试里的价值在于体力活:读响应、抄字段、整理时间线、把碎片拼成一份结构完整的草稿。 AI 的危险也在于此:它不承担法律责任,却可能替你把请求打到不该打的地方,或者把一份没验证过的 结论写进提交给平台的报告。

这个项目的边界设计就是把这两件事分开:

  • AI 负责:调用工具、读取结果、结构化整理、生成草稿、跟踪状态。

  • 人负责:登记授权、批准每一次出网、复核每一条结论、在平台网页上点击提交。

  • 代码负责:让上面这条分工无法被配置绕过。范围校验器没有 force 参数,确认令牌是一次性的, 审计记录不允许静默删除。

换句话说:合规不写在文档里,写在执行管线里。


核心安全设计

16 条约束,以及它们在代码中的唯一落地点:

#

约束

落地位置

1

默认拒绝、无强制通过:没有匹配到授权就是 DENY;不存在 force / skip / override 参数

src/mcp_vulbox_agent/security/scope.py;config/config.yaml 的 authorization.default_decision: deny、allow_force_pass: false(后者在 config.py 中被硬约束禁止开启)

2

全局拒绝优先:云元数据网段、组播、保留地址在代码中写死,与 scope.yaml 取并集,任何配置都覆盖不掉

security/scope.py 的 BUILTIN_GLOBAL_DENY + config/scope.yaml 的 global_deny

3

授权过期即失效:valid_to 之后自动 DENY,无需人工干预

models.py 的 Authorization.is_valid_at() / .expired

4

先规范化再比对:http://EXAMPLE.com:80/../x 这类写法不可能绕过字符串比对

security/target.py,网络层只接受 NormalizedTarget

5

出网模式硬闸:只有 live 模式允许出网

tools/context.py 的 NETWORK_MODES = frozenset({RunMode.LIVE})

6

主动工具默认全关、双白名单:配置与 MCP_VULBOX_*_TOOLS 环境变量必须同时列名

tools/registry.py 的 _is_enabled()

7

人工确认令牌绑定「工具 + 规范化目标 + 参数哈希」且只能消费一次

security/confirmation.py(HMAC-SHA256,密钥只从环境变量读)

8

确认密钥缺失即 fail-closed:没配 MCP_VULBOX_CONFIRMATION_SECRET 时所有主动工具无法启用

config.py 的 Secrets.confirmation_secret

9

三道限流闸门同时生效:令牌桶(速率)+ 并发闸门 + 请求预算,触发即拒绝、不排队不重试。限流由出网 handler 在构造网络客户端时注入,因此只有真正要发请求的工具才占用配额

security/ratelimit.py;tools/active.py / tools/high_risk.py 的 ctx.new_limiter()

10

硬上限只能更保守:配置超过 HARD_LIMITS 直接报错,不静默夹取

config.py 的 HARD_LIMITS 与 _within_hard_limits()

11

唯一网络出口 + 不跟随重定向 + 强制 robots.txt

net.py(follow_redirects=False 硬编码;respect_robots_txt 为硬约束禁止关闭)

12

载荷白名单:只接受内置安全库中的 check_id,且 24 类禁止检查类型写死在配置里

tools/high_risk.py 的 load_safe_checks();config/safe_checks.yaml 的 forbidden_check_types

13

证据落盘前强制脱敏 + 三重限额

security/redaction.py;storage/evidence_store.py(类型白名单 → 单文件/单发现数量/单发现总量 → 脱敏 → 落盘)

14

提示词注入检测与隔离:工具输出一律视为不可信数据,命中即整段丢弃并隔离到人类专属通道

security/injection.py 的 guard_result();security/quarantine.py

15

审计 append-only、不可静默删除:只有 AuditLog.purge() 一条删除路径,且要求显式确认 + 操作者 + 先留痕

security/audit.py;config.audit.allow_silent_delete: false(禁止开启)

16

不存在自动提交能力:这是设计约束而非配置项

vulbox/base.py 的 submit_report 永远抛错;config.report.auto_submit: false(禁止开启)

违规调用(范围拒绝、确认缺失、注入命中、模式越界)会自动打 alert=True, 错误码集合见 errors.py 的 ALERTING_ERROR_CODES,可用 mcp-vulbox-agent audit query --alerts 过滤。


架构

flowchart TD
    A["Agent(MCP 客户端)"] -->|"stdio / MCP 协议"| S["MCP Server<br/>src/mcp_vulbox_agent/server.py"]

    S --> R["ToolRegistry.execute()<br/>tools/registry.py<br/>(唯一调用入口,无旁路)"]
    S --> CAT["catalog.py<br/>resources + prompts<br/>(只读文本,无执行路径)"]

    R --> P["执行管线"]
    P --> P1["1 启用校验<br/>_is_enabled"]
    P1 --> P2["2 模式校验<br/>NETWORK_MODES"]
    P2 --> P3["3 范围校验<br/>ScopeGuard.check"]
    P3 --> P4["4 人工确认<br/>HMAC 一次性令牌"]
    P4 --> P5["5 执行 handler<br/>出网工具在此内部限流"]
    P5 --> P6["6 输出清洗<br/>guard_result"]
    P6 --> P7["7 审计落盘<br/>append-only JSONL"]

    P5 --> T1["被动层 16 个工具<br/>tools/passive.py<br/>不出网 / 不需确认"]
    P5 --> T2["主动层 3 个工具<br/>tools/active.py<br/>出网 / 需确认 / 默认关闭"]
    P5 --> T3["高风险层 3 个工具<br/>tools/high_risk.py<br/>出网 / 需确认 / 默认关闭"]

    CAT -.->|"vulbox://scope 经 auth_list 取数<br/>(同一路径,同样进审计)"| T1
    CAT -.->|"vulbox://skills/{name} 读 skills/"| SK["skills/*/SKILL.md"]

    T1 --> ST["存储层"]
    T2 --> ST
    T3 --> ST
    ST --> D1["SQLite 状态库<br/>data/state.db"]
    ST --> D2["证据库<br/>data/evidence/"]
    ST --> D3["审计日志<br/>data/audit/*.jsonl"]
    ST --> D4["注入隔离区<br/>data/quarantine/"]

    T1 -.-> V["Vulbox 适配层<br/>vulbox/mock | manual | live<br/>只读 + 人工导出"]
    V -.->|"旁挂:仅被动工具调用"| S

    NET["net.py<br/>唯一 HTTP 出口<br/>robots.txt / 不跟随重定向 / 响应体硬上限"] --- T2
    NET --- T3

管线顺序在 tools/registry.py 的 _run_pipeline() 中按注释编号固定, tools/__init__.py 的 docstring 也重复声明了「没有旁路」——任何绕过安全内核直连网络的代码路径都属于缺陷。


目录结构

mcp-vulbox-agent/
├── .dockerignore                    # 构建上下文排除(.env 绝不进镜像)
├── .env.example                     # 环境变量模板(只允许占位符)
├── .gitignore
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.yml
│   │   └── feature_request.yml
│   ├── workflows/
│   │   ├── ci.yml                   # ruff + mypy + pytest + stdio 验收(3.11/3.12/3.13)
│   │   ├── security.yml             # bandit + pip-audit(每周)
│   │   └── release.yml              # tag v* → 构建 + GitHub Release
│   └── PULL_REQUEST_TEMPLATE.md
├── Dockerfile                       # 两阶段构建,非 root,默认 offline
├── docker-compose.yml               # stdio 服务 + 可选 sse profile(只绑 127.0.0.1)
├── pyproject.toml                   # 依赖 / ruff / mypy / pytest 配置
├── README.md
├── SECURITY.md
├── CONTRIBUTING.md
├── CODE_OF_CONDUCT.md
├── LICENSE
├── config/
│   ├── config.yaml                  # 主配置:限额、证据、审计、报告、授权、工具白名单
│   ├── safe_checks.yaml             # 载荷白名单(payloads)+ 被动检查目录 + 禁止检查类型
│   └── scope.yaml                   # 授权范围定义(唯一真相源)
├── docs/
│   ├── COMPLIANCE.md                # 合规声明
│   ├── AI-USAGE.md                  # AI 使用声明
│   ├── DEPLOYMENT.md                # 部署与运维
│   └── DISCLAIMER.md                # 免责声明
├── skills/                          # Agent 技能层(操作规程,非代码)
│   ├── README.md                    # 技能索引 + 四条铁律
│   ├── authorization_check/SKILL.md # 开工前授权检查
│   ├── scope_parse/SKILL.md         # 范围解析成允许/禁止清单
│   ├── asset_discovery/SKILL.md     # 被动优先建资产清单
│   ├── fingerprint/SKILL.md         # 指纹识别
│   ├── safe_vuln_verify/SKILL.md    # 非破坏性验证
│   ├── evidence/SKILL.md            # 脱敏证据管理
│   ├── report/SKILL.md              # 报告草稿与人工提交登记
│   └── human_review/SKILL.md        # 只能由人类完成的动作
├── src/mcp_vulbox_agent/
│   ├── __init__.py                  # PROJECT_POSITIONING / __version__
│   ├── __main__.py                  # python -m mcp_vulbox_agent → MCP Server (stdio)
│   ├── catalog.py                   # MCP resources + prompts(服务面的另一半)
│   ├── cli.py                       # CLI 全部子命令(人类操作面唯一入口)
│   ├── config.py                    # 配置加载 + HARD_LIMITS 硬约束校验
│   ├── errors.py                    # 错误码 + 合规替代方案
│   ├── models.py                    # 数据模型(目标、授权、证据、草稿、审计记录)
│   ├── net.py                       # 唯一 HTTP 出口(robots / 限流 / 预算都在这里)
│   ├── server.py                    # MCP Server 入口与工具注册
│   ├── security/                    # 安全内核:所有约束的唯一落地点
│   │   ├── __init__.py
│   │   ├── audit.py                 #   不可静默删除的审计
│   │   ├── confirmation.py          #   一次性 HMAC 确认令牌
│   │   ├── injection.py             #   提示词注入检测 / 输出清洗
│   │   ├── quarantine.py            #   注入隔离区(人类专属读)
│   │   ├── ratelimit.py             #   令牌桶 + 并发闸门 + 请求预算
│   │   ├── redaction.py             #   证据与日志脱敏
│   │   ├── scope.py                 #   范围校验(无强制通过)
│   │   └── target.py                #   目标规范化
│   ├── storage/
│   │   ├── __init__.py
│   │   ├── db.py                    # SQLite 连接与建表
│   │   ├── evidence_store.py        # 证据落盘(脱敏 + 限额 + 保留期)
│   │   └── repository.py            # 实体读写
│   ├── tools/
│   │   ├── __init__.py
│   │   ├── active.py                # 3 个主动工具
│   │   ├── context.py               # ToolContext 装配
│   │   ├── high_risk.py             # 3 个高风险工具
│   │   ├── passive.py               # 16 个被动工具
│   │   └── registry.py              # 注册表 + 唯一执行管线
│   └── vulbox/
│       ├── __init__.py              # build_adapter 工厂
│       ├── base.py                  # 适配器接口(submit_report 永远抛错)
│       ├── live.py                  # 只读公开 API
│       ├── manual.py                # 人工导入/导出,零网络
│       └── mock.py                  # 本地 mock,默认
├── tests/
│   ├── conftest.py                  # 共享 fixture(数据根一律 tmp_path)
│   ├── test_catalog.py              # MCP 资源与提示词(含路径穿越拒绝)
│   ├── test_config_discovery.py     # 配置发现与 PROJECT_ROOT 推导
│   ├── test_mcp_protocol.py         # MCP 协议层 schema 与工具层模型一致
│   ├── test_net_query.py            # 查询串传递与网络出口约束
│   ├── test_redaction.py            # 脱敏规则
│   ├── test_registry_pipeline.py    # 执行管线与各拒绝路径
│   ├── test_report_workflow.py      # 发现→证据→草稿→复核→登记 全链路
│   ├── test_scope_guard.py          # 范围校验
│   └── test_vulbox_adapters.py      # 三种适配器与能力声明
└── stdio_acceptance.py              # 真实 MCP 客户端 stdio 端到端验收脚本

安装

要求 Python 3.11+(pyproject.toml 的 requires-python = ">=3.11")。

git clone https://github.com/luo173176/mcp-vulbox-agent.git
cd mcp-vulbox-agent

python -m venv .venv
# Windows: .venv\Scripts\activate
source .venv/bin/activate

pip install -e ".[dev]"

配置 .env

cp .env.example .env

然后必须生成确认密钥,否则所有主动工具无法启用(fail-closed,这是设计行为不是 bug):

python -c "import secrets;print(secrets.token_urlsafe(48))"

把输出填进 .env 的 MCP_VULBOX_CONFIRMATION_SECRET=。

.env 已被 .gitignore 忽略。.env.example 中只允许出现占位符—— 任何真实凭证被提交都按安全事故处理。

自检

mcp-vulbox-agent doctor

会逐项检查 Python 版本、依赖、运行模式、适配器、数据目录、确认密钥、授权条目数、 审计开关、主动工具启用数、外部工具路径与硬上限。有 fail 项时退出码为 1。

当前仓库的 .venv 里尚未执行过 pip install -e,直接 python -m mcp_vulbox_agent 会报 No module named mcp_vulbox_agent(src 布局)。先安装,或临时用 PYTHONPATH=src。


快速开始

1. 用 MCP Inspector 连上(stdio 形式)

npx @modelcontextprotocol/inspector \
  mcp-vulbox-agent serve

或者用模块入口(等价):

npx @modelcontextprotocol/inspector \
  python -m mcp_vulbox_agent

两个入口都启动同一个 stdio 传输的 MCP Server。启动成功后 stderr 会打印一行:

[mcp-vulbox-agent] 启动:模式=offline 适配器=mock 工具=16被动+6主动 确认密钥=未配置

看到 确认密钥=未配置 时,主动工具调用会被拒绝。

2. 用 CLI 看工具清单

CLI 是人类操作面的唯一入口。先看清单:

mcp-vulbox-agent tools list
mcp-vulbox-agent tools describe http_probe

tools list 会列出每个工具的名字、类别、启用状态、是否出网、是否需要人工确认、是否需要目标参数。 tools describe <name> 会额外打印参数的 JSON Schema。

只读校验一个目标:

mcp-vulbox-agent scope check https://demo.example.invalid/
mcp-vulbox-agent scope list

12 步典型工作流

每一步都标了是否需要人类介入。标了 👤 的步骤 Agent 做不了,这不是权限问题,是没有对应的工具。

步

动作

执行者

1

在 config/scope.yaml 登记授权:authorization_id / program_id / source / evidence_ref(书面授权引用) / valid_from / valid_to / scope / deny

👤 人工

2

生成 MCP_VULBOX_CONFIRMATION_SECRET 并写入 .env;mcp-vulbox-agent doctor 确认无 fail 项

👤 人工

3

调用 scope_check 校验目标,拿到 allow / deny、命中的授权 ID、生效速率上限。deny 时不要换工具重试

Agent

4

调用 auth_list 读取已登记授权;调用 vulbox_programs 读取平台侧项目(mock/manual 适配器零网络)

Agent

5

调用 asset_list / asset_add 建立本地资产清单;vulbox_assets 逐条标注是否在授权范围内

Agent

6

调用被动工具做离线整理:finding_create 建草案、evidence_save 存证据(落盘前强制脱敏)、finding_list / evidence_list 复核

Agent

7

若要出网:在 config/config.yaml 的 tools.enabled_active 与环境变量 MCP_VULBOX_ACTIVE_TOOLS 中同时列名(高风险工具同理走 enabled_high_risk / MCP_VULBOX_HIGH_RISK_TOOLS),并把 MCP_VULBOX_MODE 切到 live

👤 人工

8

调用主动工具(如 http_probe)。首次不带令牌 → 返回 CONFIRMATION_REQUIRED 与一个 confirmation_id,附带完整的绑定摘要(工具、目标、参数哈希、范围校验结果、限流、影响面)

Agent

9

用 mcp-vulbox-agent confirm show <id> 看清影响面,再 confirm approve <id> --actor <你的名字> 批准,拿到一次性令牌

👤 人工

10

带着令牌重试第 8 步的调用 → 真正出网执行(受限流与请求预算约束),结果写入审计

Agent

11

调用 report_generate_draft 生成草稿:带固定水印、6 项人工复核清单、4 条提交指引

Agent

12

mcp-vulbox-agent report show <draft_id> 逐项复核 → 调 report_set_review(status=approved,需填 actor)→ 👤 在平台网页提交 → 调 report_mark_submitted 回填平台报告编号 → 调 report_platform_status 跟踪状态

👤 + Agent

第 12 步的最后一段值得再强调一次:提交动作永远由人类在平台网页上完成, report_mark_submitted 只是把「已经提交了、编号是 X」这件事记进本地状态库。


工具清单(22 个)

被动 16 个:不出网(requires_network=false)、不需要人工确认。带 target 参数的工具 (scope_check 与 finding_create)仍会走管线第 3 步范围校验——范围判定只有一处实现, 漏一个工具就漏掉一整条越界痕迹。scope_check 是唯一例外,因为它本身就是范围查询。

工具名

类别

出网

需确认

说明

scope_check

passive

✗

✗

校验目标是否在已登记授权范围内。**所有主动操作前必须先调用。**返回 allow/deny、命中的授权 ID、生效速率上限。可选 tool_name 参数会一并按该授权的 allowed_tools 判定,用于在发起主动调用前预判工具是否被放行

auth_list

passive

✗

✗

列出已登记的授权(含有效期、范围规则数、速率上限)

asset_list

passive

✗

✗

列出本地资产清单。资产来自人工录入或平台导出,不来自主动扫描

asset_add

passive

✗

✗

录入一条资产,自动做范围标注(标注 ≠ 授权)

finding_create

passive

✗

✗

创建发现草案。target 走管线范围校验,命中的授权必须与 authorization_id 一致;severity_hint 只是提示,不自动定级

finding_list

passive

✗

✗

列出发现草案

evidence_save

passive

✗

✗

保存证据。落盘前强制脱敏;单发现数量与总量有限额

evidence_list

passive

✗

✗

列出某发现下的证据及其脱敏命中统计

report_generate_draft

passive

✗

✗

生成报告草稿(本地文件 + 状态库)。这不是提交动作

report_get_draft

passive

✗

✗

读取报告草稿全文

report_set_review

passive

✗

✗

记录人工复核结论(pending / approved / rejected)

report_mark_submitted

passive

✗

✗

回填人工在平台网页完成的提交结果。要求草稿已 approved

report_platform_status

passive

✗

✗

查询本地登记的平台报告处置状态(只读跟踪)

vulbox_programs

passive

✗

✗

列出平台侧授权项目(mock/manual 适配器零网络)

vulbox_assets

passive

✗

✗

列出平台侧公开资产并逐条标注是否在授权范围内

audit_query

passive

✗

✗

查询审计记录。alerts_only=true 只返回违规调用告警

主动 3 个:出网、需要一次性人工确认令牌、默认关闭。

工具名

类别

出网

需确认

说明

影响面

http_probe

active

✓

✓

对单个目标发起一次只读请求(GET/HEAD),返回状态码、安全化响应头、Cookie 名称(不含值)与正文预览。不做路径爆破、不做参数变异、不跟随重定向、遵守 robots.txt

1 次只读请求,等价于一次普通浏览器访问

tech_detect

active

✓

✓

被动指纹识别:读取一次响应,按内置规则推断技术栈。不发送探测载荷、不枚举路径、不做版本爆破

1 次 GET,无载荷、无枚举、无写入

tls_check

active

✓

✓

读取 https 目标的 TLS 证书公开字段(颁发者、到期时间、剩余天数、TLS 版本)。不保存证书链、不尝试绕过校验

1 次 TLS 握手

高风险 3 个:出网、需要一次性人工确认令牌、默认关闭,且额外受载荷白名单约束。

工具名

类别

出网

需确认

说明

影响面

injection_verify

high_risk

✓

✓

注入类发现的存在性验证(不是利用)。用内置载荷白名单中的成对布尔载荷比较响应形状差异(状态码/长度/词数/错误关键词,不留正文),输出 suspicious / not_reproduced。不接受自定义载荷(PAYLOAD_NOT_ALLOWED)

2 次只读请求;不提取数据、不落文件、不建会话;请求数硬上限 8

xss_probe

high_risk

✓

✓

XSS 反射验证:发送无执行能力的标记字符串,检查是否原样出现在响应中并给出上下文提示。载荷不含 <script>、不含事件属性

1 次只读请求;不会在目标浏览器中执行任何脚本

access_control_probe

high_risk

✓

✓

越权判定验证:用基线身份与对照身份各发一次只读 GET,比较响应可见性差异。不修改资源、不遍历用户 ID、不提权

2 次只读 GET(不同身份凭证);无写入、无枚举


Agent 技能层(skills/)

工具层的每道闸门(范围校验、人工确认、限流、脱敏)都是单次调用级别的约束。 它们拦得住「这一次调用越界了」,拦不住「这个 Agent 的整体打法越界了」—— 比如逐个子域去试、把一次验证拆成两百次请求、把 suspicious 直接写成 confirmed。

skills/ 补的就是这一层:8 份写给 Agent 的操作规程,每份都写了做什么、按什么顺序、 绝不能做什么。

技能

何时用

用的工具

出网

需确认

authorization_check

开工前第一件事

vulbox_programs auth_list scope_check

✗

✗

scope_parse

把范围翻成允许/禁止清单

auth_list

✗

✗

asset_discovery

建资产清单(被动优先)

vulbox_assets asset_add asset_list

✗

✗

fingerprint

识别技术栈,为验证选 check

tech_detect http_probe tls_check

✓

✓

safe_vuln_verify

非破坏性验证

injection_verify xss_probe access_control_probe

✓

✓

evidence

存脱敏证据

evidence_save evidence_list

✗

✗

report

生成草稿、跟踪状态

report_* finding_create

✗

✗

human_review

把该人做的事交回给人

无(CLI 动作)

✗

人做

技能是纯 Markdown,自足且无依赖。宿主支持技能目录就加进搜索路径,否则按需把 SKILL.md 喂进上下文即可。索引与四条铁律见 skills/README.md。


MCP 服务面:资源与提示词

MCP 的服务面由三部分组成。本项目三样都提供,且后两者刻意做得很窄。

资源(resources)

资源让 Agent 不必调工具就能知道"现在被允许测什么"。共 3 个静态资源 + 1 个模板:

URI

内容

vulbox://scope

已登记的授权条目(项目、有效期、范围规则、deny 规则、速率上限)

vulbox://tools

22 个工具的类别、是否出网、是否需要人工确认、影响面

vulbox://skills

8 份技能的索引(用途、涉及工具、是否出网、是否需确认)

vulbox://skills/{name}

单份技能的完整规程正文

两条硬约束:

  1. 资源不引入新能力。 vulbox://scope 的数据是经 registry.execute("auth_list", …) 取的——与工具调用同一条路径。所以资源里看到的内容与工具返回的逐字节相同 (不会出现"资源说可以、工具说不行"这种最坏的分歧),且这次读取照样进审计。 资源是第二条读取路径,但不是第二条不受审计的路径。

  2. {name} 走白名单查表,不拼路径。 URI 模板参数是调用方可控输入;实现里先在 已知技能中查一次,查不到直接拒绝。vulbox://skills/../../etc/passwd 在 SDK 的 URI 路由层就被挡下,我们的白名单是第二道——两道都要在。

URI 用自定义 vulbox:// scheme 而非 file://:后者会让客户端以为能读任意路径。

提示词(prompts)

提示词只产出文本,不触发任何工具调用。因此这里写的是"按什么顺序做、在哪一步 停下来找人",而不是"替我做完"。

提示词

参数

作用

start_authorized_test

program_id target

开工五步:读规程 → 查授权 → scope_check → 确认工具放行 → 才继续。点名 force_pass 这类不存在的旁路参数

verify_finding_safely

target param check_id

非破坏性验证:只许用内置载荷库、需人工确认、suspicious 不等于漏洞成立

draft_report

program_id title

整理草稿:登记发现 → 存脱敏证据 → 生成草稿;明写不存在自动提交

review_before_submit

draft_id

把复核清单原样交给人;未 approved 时不许 report_mark_submitted

复核清单与提交指引来自 tools/passive.py 的 REVIEW_CHECKLIST / SUBMIT_INSTRUCTIONS 常量——唯一副本,报告草稿与提示词都引用它。分成几份写迟早会漂移,而漂移的那 一份就是复核时被漏掉的那一条。


常见拒绝场景与合规替代方案

系统被拒绝时,ToolResult.alternative 字段会给出可执行路径(来自 errors.py 的 COMPLIANT_ALTERNATIVES)。 下面是几个最容易踩到的:

1. 目标越界

会看到:SCOPE_DENIED / GLOBAL_DENY_HIT / AUTHORIZATION_EXPIRED / AUTHORIZATION_MISSING

目标未通过范围校验:目标不在任何已登记授权范围内

正确做法:先在 config/scope.yaml 登记授权(evidence_ref 必填书面授权引用), 或改用已授权项目内的等价目标,或仅对该目标做完全离线的文档/配置审查。 命中 GLOBAL_DENY_HIT(云元数据网段、组播地址)时没有任何替代路径——该列表不可被配置覆盖。

2. 未确认的主动调用

会看到:CONFIRMATION_REQUIRED

工具 http_probe 需人工确认。已生成确认请求 cnf_xxxxxxxx。
请由人类执行:mcp-vulbox-agent confirm approve cnf_xxxxxxxx --actor <你的名字>

正确做法:把 confirmation_id 交给人类,由人类在 CLI 中 approve。 令牌与「工具 + 规范化目标 + 参数哈希」绑定,换目标或换参数即失效,且只能消费一次。 不要尝试复用旧令牌(CONFIRMATION_MISMATCH)。

3. 要求自动提交

会看到:注册表中没有提交类工具,调用会得到 UNKNOWN_TOOL; 若草稿未通过复核就调 report_mark_submitted,会得到 REPORT_INCOMPLETE:

草稿尚未通过人工复核(review_status != approved),不能登记为已提交。请先完成逐项复核。

正确做法:report_generate_draft 生成草稿 → 人类逐项复核 → report_set_review 标 approved → 人类在平台网页上提交 → report_mark_submitted 回填编号。

4. 要求自定义注入载荷

会看到:PAYLOAD_NOT_ALLOWED

本系统只接受内置安全载荷库中的非破坏性验证载荷,不接受自定义注入串或武器化 EXP。

正确做法:用 config/safe_checks.yaml 中已登记的 check_id 重试; 若确有新的验证需求,先由人类评审并把载荷写入该文件(含影响说明); 或改用离线样本在隔离环境分析。

5. 要求无人值守

会看到:TOOL_DISABLED(工具未启用)或 MODE_NOT_ALLOWED(offline 模式不允许出网)

工具 http_probe 未启用(类别:active)。主动工具需要在 config.yaml 与环境变量中**同时**列入白名单。

正确做法:没有无人值守模式,也没有批量目标参数——这是设计而非缺陷。 需要跑量时,由人类逐次批准,或把目标交给平台的官方扫描能力,而不是这个工作台。

6. 工具输出疑似包含提示词注入

会看到:INJECTION_SUSPECTED,且 data 被整段丢弃、只留隔离说明与哈希

正确做法:用 mcp-vulbox-agent quarantine show <entry_id> 由人类查看原文 (读取本身写入审计);或更换目标页面、改用离线样本继续分析。 注意:被测系统自身包含注入文本,往往恰恰是漏洞证据,所以隔离不等于删除。


合规与法律声明

使用本项目前请阅读:

  • docs/COMPLIANCE.md —— 适用法律、授权要求、数据最小化、平台规则、留存与删除、违规拒绝清单

  • docs/AI-USAGE.md —— AI 在本项目中的角色边界、水印、人工复核清单、提示词注入防护

  • docs/DISCLAIMER.md —— 免责声明

  • SECURITY.md —— 安全模型、威胁边界、漏洞报告流程

一句话:只允许用于自有资产、明确书面授权的目标、靶场、或平台授权项目。 使用者对自己的一切行为负责。


验收清单

下面每一条都能在本机复现,且结果写明了实测输出。复现前先按安装建好 venv、 按配置 .env 生成确认密钥,然后执行:

export PYTHONPATH=src          # Windows: $env:PYTHONPATH="src"
export PYTHONIOENCODING=utf-8  # Windows: $env:PYTHONIOENCODING="utf-8"

#

标准

复现命令

实测结果

1

docker compose up 可启动

docker compose run --rm mcp-server doctor

自检通过,退出码 0。容器内 Python 3.11.17,授权条目 2 条、全局拒绝 5 条,主动工具 6 个已启用 0 个。唯一 warn 是「确认密钥未配置」——compose 未挂载 .env 时的预期结果,配置后即消失

2

MCP Inspector 能看到全部合规工具

npx @modelcontextprotocol/inspector mcp-vulbox-agent serve(同快速开始)

list_tools() 返回 22 个工具,每个都带 input_schema。无 vulbox_submit_report;名字含 submit 的只有 report_mark_submitted(被动、不出网、只登记状态)。另有 resources/list 3 项 + 1 个模板、prompts/list 4 项

3

mock 环境跑通完整流程

pytest tests/test_report_workflow.py -q

39 passed:发现 → 证据 → 草稿 → 复核 → 人工提交登记

4

scope guard 阻止越界且无强制通过选项

见下方 4a / 4b

deny / not_in_scope;force_pass 被 INVALID_ARGUMENT 拒绝

5

主动工具默认关闭,需显式启用 + 人工确认

pytest tests/test_registry_pipeline.py -k disabled -q

全部返回 TOOL_DISABLED;启用后仍需确认令牌

6

不存在自动提交工具

pytest tests/test_registry_pipeline.py -k submission -q

唯一含 submit 的是 report_mark_submitted(登记,非提交);adapter.submit_report() 恒抛 MODE_NOT_ALLOWED

7

能生成报告草稿并提示人工复核

见下方 7

水印 AI 辅助生成,需人工验证,6 项复核清单,5 步提交说明

8

证据保存前自动脱敏

见下方 8

[REDACTED:authorization_header] / [REDACTED:cn_phone] / [REDACTED:email],needs_manual_review=true

9

审计完整且敏感字段脱敏

见下方 9

越界调用进 alerts(),记录 deny / not_in_scope;审计全文不含 token、手机号、邮箱

10

能拒绝越界 / 无人值守 / 自动提交 / 武器化请求

见下方 10

四类各有明确错误码与合规替代方案

11

pytest、ruff、mypy 通过

pytest && ruff check src tests && mypy src

326 passed;All checks passed!;Success: no issues found in 33 source files

12

新用户 10 分钟内跑起来且边界清晰

按快速开始逐步执行

从零到 scope_check 返回 allow 约 5 分钟

第 2 条另有端到端实证:python stdio_acceptance.py 用真实 MCP 客户端连上 服务进程(JSON-RPC 经管道),逐项核对资源、模板、提示词与路径穿越拒绝, 共 17 项断言全通过——直接调 build_server() 验证的是"对象上挂着什么", 只有真连一次才能发现 schema 不被识别、模板参数名对不上这类问题。

4a. 越界目标被拦

mcp-vulbox-agent scope check https://evil.example.com/
# → deny / not_in_scope

mcp-vulbox-agent scope check http://169.254.169.254/
# → deny / global_deny(云元数据,写死的全局拒绝,不可协商)

4b. 不存在强制通过参数

registry.execute("scope_check", {"target": "...", "force_pass": True}, ctx)
# → INVALID_ARGUMENT: 参数校验失败(1 处):force_pass: Extra inputs are not permitted

参数模型是 extra="forbid",force_pass / ignore_scope / skip_check 这类字段 在参数层就被拒,连范围校验都到不了。代码里也没有任何 force / override 开关。

7. 草稿带水印与复核清单

mcp-vulbox-agent report show <draft_id>
# → watermark: AI 辅助生成,需人工验证
#   review_checklist: 6 项
#   submit_instructions: 5 步
#   review_status: pending

草稿处于 pending 时调用 report_mark_submitted 会得到 REPORT_INCOMPLETE—— 未复核的报告连「登记为已提交」都不允许。复核后 review_status 变 approved, 并记下 reviewed_by(谁复核的),此时才允许登记。

8. 证据落盘前脱敏

输入含 Authorization: Bearer sk-live-...、邮箱、手机号的响应头,落盘后:

[REDACTED:authorization_header]
contact: [REDACTED:email]
phone [REDACTED:cn_phone]
Strict-Transport-Security: (absent)

redaction_hits 返回命中类别与次数,needs_manual_review=true 表示含个人信息类命中, 必须人工复核后才允许上传(EvidenceStore.assert_uploadable 会拦)。

9. 审计留痕与脱敏

被拒的调用恰恰是最需要留痕的一类。一次越界 finding_create 之后:

mcp-vulbox-agent audit query --alerts
# → SCOPE_DENIED,scope_decision=deny,scope_reason=not_in_scope

审计文件是 JSONL 按天分片,追加写 + fsync,allow_silent_delete 硬约束为 false, 删除必须显式 --actor + --yes + 交互确认(配置了 MCP_VULBOX_PURGE_SECRET 时还需 --secret)。 实测审计全文不含 token、手机号、邮箱。

10. 四类越界请求的拒绝输出

请求

错误码

拒绝理由

扫描授权范围外的目标

SCOPE_DENIED

目标不在任何已登记授权范围内

要求无人值守连续运行

CONFIRMATION_REQUIRED

主动工具每次调用都要新的确认令牌

要求自动提交报告

MODE_NOT_ALLOWED

本系统不存在自动提交能力,这是设计约束而非配置项

要求自定义注入载荷

INVALID_ARGUMENT / PAYLOAD_NOT_ALLOWED

参数模型不含 payload 字段;载荷只从内置库取

每一类都带 alternative 字段给出合规替代方案,而不是只说「不行」。


开发指南

# 静态检查与格式
ruff check src tests stdio_acceptance.py
ruff format --check src tests stdio_acceptance.py

# 类型检查(strict 模式)
mypy src

# 测试
pytest
pytest --cov=mcp_vulbox_agent --cov-report=term-missing

# MCP 协议端到端验收(真实 stdio 握手,核对 resources / prompts / 路径穿越拒绝)
python stdio_acceptance.py

配置说明(全部来自 pyproject.toml):

  • ruff:line-length = 88、target-version = "py311", lint 规则集含 S(bandit 安全类,必须开)、T20(禁止裸 print)、DTZ(强制时区感知)、 PTH、ARG、RET、PIE、PT、TC 等。E501 与 RUF001/002/003 被忽略—— 中文全角标点是本项目的既定文风,不是「歧义字符」。

  • mypy:strict = true、warn_unreachable、warn_unused_ignores、disallow_untyped_defs。

  • pytest:asyncio_mode = "auto"、--strict-markers --strict-config, 自定义 marker:slow、integration。

贡献前请读 CONTRIBUTING.md —— 里面列了不得新增的能力类型。


License

MIT License,见 LICENSE。

Copyright (c) 2026 mcp-vulbox-agent contributors

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    An MCP server for authorized bug bounty work that enforces an evidence-driven workflow with session management, preflight checks, surface discovery, and verified scanning.
    12
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables authorized bug bounty automation via a scope-enforced MCP bridge, supporting web, secrets, mobile, and LLM red-team scanning, with reporting and advisory.
    MIT
  • A
    license
    C
    quality
    B
    maintenance
    Enables authorized pentest and bug bounty workflows from any MCP client, with scoped recon, per-host rate limits, and scanner output turned into deduplicated, triaged finding cards.
    9
    43 PyPI
    2
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables authorized penetration testers to run reconnaissance, scanning, brute-force, exploitation, traffic capture, wordlist generation, and client-report workflows through MCP clients, with stdio/HTTP/SSE transport and OIDC bearer authentication.
    81 npm
    GPL 3.0