自动漏洞验证SKILL设计

面向企业测试内网的白盒漏洞动态验证SKILL。核心不是重新发现漏洞,而是把上游报告中的verification_handoff编译成独立、可调度、可恢复的单case任务,执行真实PoC并保存证据,最后形成可复核的三态验证报告。

通用SKILL组织原则参考Agent SKILL设计

当前版本:2.1.1

定位

这个SKILL主要处理:

  • 消费白盒报告中的verification_handoff
  • 校验测试目标、身份和运行前置条件;
  • 为每个漏洞编译独立的单case task;
  • 在授权测试内网中通过宿主可用的HTTP客户端执行PoC;
  • 根据实际响应调整报告允许调整的PoC细节;
  • 保存逐次网络交互、实际客户端、oracle判断和结论依据;
  • 支持最多3个无冲突单case执行器并发;
  • 在没有子Agent/Worker时由主Agent完整顺序执行;
  • 在结构化HTTP工具不可用或不能表达请求时回退到已有curl等命令行客户端;
  • 汇总所有case并生成VULNERABILITY_VERIFICATION_REPORT.md

明确不处理:

  • 漏洞发现;
  • 源码审计;
  • 重新判断漏洞类型;
  • 根据漏洞知识库设计新的攻击路径;
  • 自动修复漏洞;
  • 修改业务源码;
  • 把一个case扩展成报告未定义的额外测试范围。

这里需要始终保持一个边界:

验证阶段执行既定flow并判断oracle,不重新承担漏洞挖掘阶段的职责。

上游报告决定要验证什么;这个SKILL负责把它可靠地执行、记录和汇总。

核心设计

整个设计拆成三层:

flowchart TD
 A[控制层<br/>SKILL / 主Agent] --> B[任务协议层<br/>tasks/case-id.json]
 B --> C[执行层<br/>单case子Agent / Worker]
 B --> D[执行层<br/>主Agent顺序回退]

 C --> E[Evidence]
 D --> E
 E --> F[Result]
 F --> A
 A --> G[run.json]
 A --> H[最终报告]

各层职责:

内容定位
控制层SKILL.md与主Agent输入校验、任务编译、调度、验收、恢复、汇总、用户交互和最终报告
任务协议层.auto-verification/tasks/<case-id>.json固化一个case的全部执行输入、策略和读写边界
执行层单case子Agent/Worker或主Agent只执行一个task,写该case的evidence和result;Pi优先使用vulnerability-verifier
数据契约references/context-schema.md定义target、run、task、result和evidence结构
报告契约assets/VERIFICATION_REPORT_TEMPLATE.md定义最终人类可读报告格式

子Agent不是第四层业务逻辑,也不是另一个SKILL。它只是任务协议的一个执行后端。

为什么使用单case task

直接把完整报告交给子Agent会产生三个问题:

  • 子Agent会重新读取大量与当前case无关的上下文;
  • workflow、身份、oracle和输出路径仍然需要它再次解释;
  • 并发执行时很难证明每个case只被一个执行者拥有。

单case task把这些不确定性提前消解:

flowchart LR
 A[白盒报告中的一个case] --> B[主Agent选择variant]
 B --> C[绑定身份和资源]
 C --> D[编译workflow与oracle]
 D --> E[单case task]
 E --> F[执行器]
 F --> G[evidence + result]

task是已编译协议,不是给执行器的研究材料。执行器不再决定:

  • 验证哪个漏洞;
  • 选择哪个variant;
  • 读取哪些源码或漏洞Reference;
  • 使用哪个身份;
  • 写入哪个结果文件;
  • 是否扩展攻击路径。

为什么不向执行器提供漏洞References

这个SKILL位于漏洞发现之后。上游已经提供:

  • 身份槽位和认证类型;
  • required capabilities;
  • workflow;
  • oracle;
  • evidence level;
  • negative control;
  • prerequisites;
  • allowed adjustments或variants。

漏洞Reference主要帮助发现和分析漏洞类型,而不是执行既定验证flow。把这些Reference交给执行器会重新引入:

  • 类型分析;
  • 攻击路径扩展;
  • 与当前case无关的上下文;
  • 对已编译task的二次解释。

因此执行器只消费task及其显式引用:

flowchart TD
 A[Task] --> B[target_ref]
 A --> C[read_scope.input_files]
 A --> D[当前case已有write_scope]

 X[漏洞Reference] -.禁止读取.-> A
 Y[源报告] -.禁止读取.-> A
 Z[run.json] -.禁止读取.-> A

若task不足以执行或判断,结论是inconclusive,而不是让执行器回到漏洞发现阶段。

完整Workflow

笔记中的执行结构严格对应SKILL.md定义的五步workflow,不额外引入正式阶段或门禁:

flowchart LR
 P1[1 初始化与门禁] --> P2[2 编译单case任务]
 P2 --> P3[3 调度与通用回退]
 P3 --> P4[4 单case执行与判定]
 P4 --> P5[5 汇总与报告]
 P5 --> DONE[completed]

可达性检查属于“初始化与门禁”;子Agent发现、Child验收和顺序降级属于“调度与通用回退”;Evidence、Result和三态判断属于“单case执行与判定”。它们是所属步骤的子流程,不是独立阶段。

运行状态

run.json.status记录运行状态,不表示另一套workflow阶段:

状态含义
initialized已创建运行上下文,尚未开始PoC
testing可达性通过,正在执行或验收case
awaiting_retry基础设施阻断,等待主Agent统一询问重试
completed全部case都有终态且最终报告已生成

case状态:

状态含义
pending已编译但尚未执行
running当前有且只有一个执行者拥有该case
verified动态证据满足全部必要oracle
not_verified完成有效验证,但oracle未满足
inconclusive环境、凭证、依赖或能力不足以评估oracle

没有skipped。报告中的每个漏洞ID都必须进入一个最终三态。

完整性优先

子Agent、HTTP扩展、命令行客户端和并发都属于执行手段,不是完整性条件。

以下问题不能导致case丢失:

  • 当前宿主没有子Agent能力;
  • 子执行器未发现或不可用;
  • child启动失败;
  • 并发执行中断;
  • child结果验收失败;
  • 某个HTTP客户端无法表达当前flow。

这些情况只改变执行路径:

flowchart TD
 A[全部已编译case] --> B{子Agent路径可用?}
 B -->|是| C[委派执行器可表达且无冲突的case]
 B -->|否| D[主Agent顺序队列]
 C --> E{结果验收通过?}
 E -->|是| F[Canonical Result]
 E -->|否| D
 D --> F
 F --> G{仍有pending case?}
 G -->|是| B
 G -->|否| H[完整性检查]

并行失败不能转化为:

  • 漏洞验证失败;
  • inconclusive
  • case遗漏;
  • 提前结束workflow。

只有目标、凭证、依赖、协议或宿主实际能力使oracle无法评估时,case才是inconclusive

实现结构

路径作用
profile_sys/skills/auto-vulnerability-verification/SKILL.md主workflow、门禁、调度、回退、判定和报告
profile_sys/skills/auto-vulnerability-verification/references/context-schema.md所有运行文件的数据契约
profile_sys/skills/auto-vulnerability-verification/assets/VERIFICATION_REPORT_TEMPLATE.md最终验证报告模板
profile_sys/skills/auto-vulnerability-verification/agents/openai.yaml界面名称、简介和默认Prompt
profile_sys/agents/vulnerability-verifier.mdPi环境下的薄单case执行器

当前不增加脚本。执行本身包含基于真实响应的有限判断;只有当重复出现确定性结构校验失败时,才值得补充专用validator。

.auto-verification是Canonical Context

聊天上下文只是临时缓存,.auto-verification/才是真正的运行上下文。

路径Source of Truth
target.json测试地址、身份和认证信息
run.json运行身份、来源指纹、状态、队列、执行模式和计数
tasks/<case-id>.json单case执行协议
results/<case-id>.jsoncase结论、attempt和oracle checks
evidence/<case-id>-attempt-<n>.json实际网络交互、客户端和可见事实
VULNERABILITY_VERIFICATION_REPORT.md面向人的最终汇总

数据关系:

flowchart TD
 R[白盒报告] --> T[tasks]
 X[target.json] --> T
 T --> E[evidence]
 E --> Y[results]
 Y --> S[run.json]
 Y --> P[VULNERABILITY_VERIFICATION_REPORT.md]
 E --> P

run.json不复制:

  • 完整白盒报告;
  • workflow;
  • 请求;
  • 响应;
  • 漏洞详情。

它只保存恢复和协调所需的最小状态。

Canonical Writer

只有主Agent可以写全局Canonical State:

flowchart TD
 A[Executor A] --> X[result/evidence A]
 B[Executor B] --> Y[result/evidence B]
 C[主Agent顺序执行] --> Z[result/evidence C]

 X --> P[主Agent验收]
 Y --> P
 Z --> P

 P --> R[run.json]
 P --> F[最终报告]

单case执行器可以写:

  • task声明的result_file
  • 匹配evidence_prefix的文件;
  • 所选客户端产生且仍位于当前evidence prefix的响应、Header、元数据或下载文件。

单case执行器不能写:

  • run.json
  • 最终报告;
  • 其他case的result或evidence;
  • task未声明的工作区文件。

主Agent同时是唯一可以:

  • 向用户提问;
  • 记录重试决定;
  • 修改执行模式;
  • 调度下一批case;
  • 合并最终计数。

写入顺序

每次网络交互和case状态都有固定写入顺序:

flowchart TD
 A[执行一次网络交互] --> B[立即更新当前attempt evidence]
 B --> C{attempt结束?}
 C -->|否| A
 C -->|是| D[更新result attempts与oracle checks]
 D --> E{case得到终态?}
 E -->|否| F[确认允许调整和max_attempts]
 F --> A
 E -->|是| G[完成final result]
 G --> H[主Agent更新run.json]
 H --> I[重新读取并验收]

核心顺序:

  • network interaction:先写evidence;
  • attempt:先完成evidence,再更新result;
  • case:先完成final result,再更新run.json
  • 下一case:前一个case重新读取并验收后才能开始。

如果把队列状态先更新、Artifact后写入,中断时就会出现“case已经完成但结果不存在”的不可恢复状态。

Snapshot与恢复

一次运行由以下信息绑定:

  • run_id
  • source.path
  • source.sha256
  • target_ref

恢复过程:

flowchart TD
 A[发现已有.auto-verification] --> B[读取run.json]
 B --> C[重新计算source.sha256]
 C --> D{报告是否一致?}
 D -->|否| E[停止合并旧结果并要求新运行]
 D -->|是| F[检查running case]
 F --> G[读取task/result/evidence]
 G --> H{最后检查点完整?}
 H -->|是| I[按replay策略继续]
 H -->|否| J[根据可确认状态决定inconclusive或恢复]

replay控制中断后的处理:

恢复动作
safe可以从最后完整检查点继续
check_state先确认目标状态,再决定是否重放
never不重放;无法确认时为inconclusive

不能根据对话记忆推断请求是否发送成功,也不能为了恢复方便重放状态未知的有副作用请求。

1. 初始化与门禁

这一步确定本轮验证到底是什么。

必须取得:

  • 用户明确给出的白盒报告路径;
  • 完整测试地址,包括scheme、host和必要base path;
  • 报告要求的测试身份;
  • 身份标签、角色和已知主体ID;
  • 跨身份case需要的对象归属或权限基线。

报告路径未提供时直接询问,不能扫描工作区、猜测文件名或自动选择候选报告。

报告契约

报告必须包含:

  • report
  • summary
  • 统一漏洞详情;
  • verification_handoff
  • coverage

正式运行前检查:

检查项要求
总数summary.cases_total等于漏洞详情数量
ID汇总与详情ID集合完全一致
元数据标题、严重性、静态状态一致
步骤数汇总steps与实际workflow一致
Schema新报告使用report.schema_version=1verification_handoff.schema_version=1;无版本旧报告仍须满足完整handoff,兼容转换不得补造攻击路径
handoff身份需求、required capabilities、结构化send、oracle、negative control和allowed adjustments完整
workflow步骤连续,或至少一个variant前置条件满足

契约错误不静默修补,也不在验证阶段重新设计flow。

测试目标和身份

target.json是地址与凭证的Canonical来源。Evidence和报告可以记录实际发送的认证信息,但不能反过来作为后续请求的凭证来源。

认证类型只支持:

  • Cookie;
  • JWT;
  • 自定义HTTP Header。

身份规则:

场景绑定要求
匿名identity_id=anonymous,移除所有配置认证Header
普通认证使用一个稳定身份ID
水平权限边界actorresource_owner是两个真实不同身份,并先建立对象归属基线
垂直权限边界low_privilegehigh_privilege角色真实不同,并先建立正常权限差异
多阶段flow每个step单独标记identity_id

不得把同一凭证复制为两个身份,也不得仅根据名称推断角色、租户或对象归属。

task与run.json只引用身份ID,不复制凭证;执行evidence和最终报告保留完整请求及认证信息。

企业测试环境策略

当前运行环境是可快速快照恢复的企业测试内网,因此策略明确为:

策略
allow_destructive_poctrue,允许已编译flow中的破坏性PoC
preserve_unredacted_outputstrue,Evidence、Result和Report保留完整信息
follow_workflow_without_scope_expansiontrue,禁止引入flow外动作或扩大范围
cleanup不由执行器设计,依赖外部快照恢复

限制的对象不是PoC的破坏性,而是执行器的主观扩张。

主Agent和所有执行器都不得:

  • 引入workflow之外的动作;
  • 引入allowed_adjustments之外的变体;
  • 增加目标范围;
  • 增加无依据的请求数量;
  • 扩大载荷规模;
  • 延长持续时间;
  • 扩大既定flow之外的影响范围。

可达性门禁

发送PoC前先执行无副作用可达性检查。

入口选择顺序:

  1. 报告明确提供的健康检查;
  2. 只读公开入口;
  3. base URL。

判断:

观察结论
任意HTTP响应网络层可达
5xx或持续API异常网络可达,但仍需判断服务是否可验证
DNS、连接、TLS、代理或超时错误基础设施问题

基础设施问题不能记为漏洞not_verified

主Agent负责:

  • 保存可达性状态;
  • 将运行切换到awaiting_retry
  • 统一询问用户是否重试;
  • 用户同意后重新执行门禁;
  • 避免无限自动重试。

工具没有提供时间、延迟或其他字段时写null,不能根据模型等待时间估算。

2. 编译单case任务

每个漏洞都编译为:

.auto-verification/tasks/<case-id>.json

这一步由主Agent完成,且所有执行后端使用同一文件。

task结构:

部分关键字段作用
运行引用schema_versionrun_idtarget_ref绑定运行与凭证来源
读取范围read_scope.input_files只允许workflow明确需要的上传或输入文件
写入范围result_fileevidence_prefix限定当前case输出
Policy破坏性PoC、完整输出、禁止范围扩展、重试和TLS策略固化企业执行边界
Case身份ID、标题、prerequisites、identity bindings固化当前验证对象和身份
Variantselected_variant由主Agent预先选择,执行器不再路由
并发parallel_saferesource_claims判断能否与其他case同时执行
恢复side_effectreplay控制隔离与中断重放
验证协议workflow、oracle、evidence level、negative control定义如何执行和判断
调整allowed_adjustmentsmax_attempts限定PoC调整空间和停止条件

Variant选择

主Agent选择第一个:

  • 前置条件满足;
  • 当前部署可执行;
  • 当前宿主有足够观察能力;
  • 能形成报告要求证据等级;

的workflow或variant。

task只保存选中的实际flow。执行器不能重新选择variant。

PoC调整

allowed_adjustments优先直接来自handoff。兼容旧报告时只允许来自:

  • 报告alternatives中明确的可执行差异;
  • 主Agent根据报告协议做出的等价规范化。

不得从漏洞描述、Reference或通用payload经验补充调整。

执行器只能在初始PoC未满足oracle后,根据实际响应选择允许调整。

max_attempts不能超过:

默认尝试 + 可解释的允许调整数量

不能把调整机制变成无边界枚举。

读取范围

执行器只能读取:

  • 当前task;
  • task中的target_ref
  • read_scope.input_files
  • 恢复当前case所需的write_scope文件。

不得加入:

  • 漏洞Reference;
  • 源报告;
  • SKILL正文;
  • run.json
  • 其他case;
  • workflow没有明确使用的工作区文件。

并发和资源声明

并发不是根据“请求看起来像GET”判断,而是根据case是否访问同一目标状态。

每个task声明:

  • parallel_safe
  • resource_claims
  • 每个资源的read|write访问。

冲突规则:

Case ACase B是否可并发
同一资源read同一资源read可以
同一资源read同一资源write不可以
同一资源write同一资源write不可以
无法可靠声明资源任意caseparallel_safe=false,独占执行

parallel_safe=false不等于不能委派,只表示它执行期间不能存在其他active case。

side_effectreplay只用于:

  • 判断并发隔离;
  • 中断恢复;
  • 防止未知状态下重复请求。

它们不改变handoff内容,也不阻止task已经声明的破坏性PoC。

3. 调度与通用回退

通用宿主能力发现

不能通过settings、package目录、磁盘上的agent定义或工具文档推断能力已经可用。正式调度前检查当前会话真实暴露的:

  • 子Agent/Worker创建、隔离、并发与完成通知能力;
  • 子执行器可用的文件读取和写入能力;
  • 主Agent与子执行器各自可用的结构化HTTP工具;
  • 命令执行能力,以及本地已经存在的curl或等价客户端;
  • 当前case要求的Browser、Callback、WebSocket、Race或其他观察能力。

只要某个子执行器能读取单个task和target_ref、使用至少一种合格客户端并写自己的Result/Evidence,就可以作为单case执行后端,不要求固定agent名、工具名或调度API。

执行模式:

条件execution.mode
存在满足单case协议的子Agent/Workersubagents
开始时没有合格子执行器sequential
运行中并行能力失效degraded-sequential

run.json.execution记录实际hostagent和按优先级发现的http_clients。并发上限为3,同时受宿主上限、依赖、资源声明和副作用约束。

HTTP客户端选择

HTTP执行按case选择实现,不要求整次运行固定一种客户端:

flowchart TD
 A[已编译单case task] --> B{结构化HTTP工具可准确表达并观测?}
 B -->|是| C[使用http或宿主等价工具]
 B -->|否| D{允许命令执行且已有curl?}
 D -->|是| E[使用curl]
 D -->|否| F{存在其他合格客户端?}
 F -->|是| G[使用宿主已有客户端]
 F -->|否| H[检查其他执行器或记录能力阻断]
 C --> I[记录实际客户端与可见性]
 E --> I
 G --> I

选择原则:

  1. 优先结构化HTTP工具。Pi中优先@evalexp/pi-http提供的http,其他宿主使用等价结构化工具。
  2. 结构化工具不存在或不能表达当前请求时,回退到已有curl;仍不满足时才考虑宿主已有的其他命令行客户端。
  3. 不为本SKILL安装客户端,不自动重试,也不把不支持的协议动作静默近似成普通请求。
  4. Header、Body、跳转、计时、TLS、代理、二进制、上传和下载必须以所选客户端真实能力为准。oracle依赖不可见事实时继续选择其他客户端;所有允许路径都不足时才是宿主能力阻断。
  5. 每个interaction记录实际客户端、structured_tool|command_line模式和可见性边界。命令行客户端产生的响应、Header、write-out元数据、下载和临时文件只能写入当前case的evidence范围。

http不可用不等于case阻断,curl不可用也不等于case阻断。只有子执行器和主Agent的全部允许执行路径都无法完成必要动作或采集充分证据时,case才是inconclusive

Pi首选适配与vulnerability-verifier

Pi是主要维护和使用的宿主。在Pi中仍要先检查当前会话实际暴露的子Agent能力,并确认vulnerability-verifier可执行;安装了pi-subagents或磁盘上存在agent文件都不能代替运行时发现。

Pi专用agent定义位于profile_sys/agents/vulnerability-verifier.md。它保持为薄执行器:

tools:
  - read
  - write
  - http
systemPromptMode: replace
inheritProjectContext: false
inheritGlobalContext: false
inheritSkills: false
defaultContext: fresh
acceptanceRole: writer

关键设计:

配置目的
tools: read, write, http只保留Pi首选单case验证所需工具
不声明extensions继承主Agent已加载的@evalexp/pi-http扩展
inheritProjectContext=false不把项目说明注入执行器
inheritGlobalContext=false不继承全局上下文
inheritSkills=false不把完整SKILL或其他Skill交给执行器
defaultContext=fresh每个case使用独立上下文
acceptanceRole=writer明确它负责写task声明的Artifact

这里不能把agent再写成一个SKILL。这个定义是Pi适配器,不是通用SKILL的运行前提。它的system prompt只保留角色协议:

  • 一次执行一个task;
  • 严格按task执行;
  • 每次网络交互后写evidence;
  • attempt结束后写result;
  • 阻断为inconclusive
  • 不询问用户;
  • 不写全局状态;
  • 不调度下一层Agent。

http来自主profile中的@evalexp/pi-http。agent只在tools中选择http,不重复配置扩展。task能被readwritehttp准确完成时优先委派给它;扩展不存在或当前flow超出该工具能力时,交给具备所需客户端的其他执行器,或由主Agent按同一task顺序执行。

当前http@0.1.1适合:

  • 常规HTTP方法;
  • 字符串Header映射;
  • raw文本、JSON、URL编码表单和multipart请求体;
  • 文件上传;
  • 响应下载;
  • 最终响应状态、URL、Header和body观察。

当前版本不能准确表达或观察:

需求限制
重复请求Header请求Header输入是字符串映射
原始HTTP framing不暴露线级原始报文
畸形请求普通HTTP客户端会规范化请求
重定向逐跳证据只暴露最终响应
精确计时工具未提供时不能估算
WebSocket不属于当前HTTP工具能力
浏览器DOM不属于当前HTTP工具能力
独立回调通道需要其他能力
竞态协调需要专门并发控制

这些限制只决定能否使用当前Pi verifier,不定义整个SKILL的能力上限。例如逐跳重定向或重复Header可以尝试由主Agent使用curl准确执行;Browser、Callback或Race则需要宿主真实提供相应能力。

无论使用哪种客户端,大响应和辅助文件都必须位于当前case的evidence_prefix。TLS校验只能在用户已接受风险且task设置allow_insecure_tls=true时,通过http.insecure=truecurl -k或等价选项关闭。

调度

调度顺序优先考虑依赖和状态冲突:

  1. 只读、匿名、响应型case;
  2. 认证和权限边界case;
  3. 写入、上传、命令、SSRF、反序列化和跨步骤case。

这个顺序是队列组织方式,不改变报告原有case集合和最终展示顺序。

并发调度:

flowchart TD
 Q[Pending Tasks] --> S[检查依赖、resource claims和工具能力]
 S --> A[Executor 1]
 S --> B[Executor 2]
 S --> C[Executor 3]

 A --> X[Result/Evidence A]
 B --> Y[Result/Evidence B]
 C --> Z[Result/Evidence C]

 X --> P[主Agent验收]
 Y --> P
 Z --> P
 P --> Q

每个case同时只能有一个执行者。一次子Agent调用只传一个task路径,不传:

  • 完整报告;
  • SKILL;
  • run.json
  • 其他case;
  • 漏洞References。

Child结果验收

子执行器返回后,主Agent不能只接受自然语言摘要。

验收内容:

flowchart TD
 A[Child返回] --> B[解析result JSON]
 B --> C[检查case ID和路径]
 C --> D[读取全部evidence引用]
 D --> E[检查attempt数量]
 E --> F[检查interactions顺序]
 F --> G[逐条检查oracle checks]
 G --> H{证据充分且契约一致?}
 H -->|是| I[更新run.json]
 H -->|否| J[一次针对性修正或重试]
 J --> K{仍失败?}
 K -->|否| I
 K -->|是| L[放回主Agent顺序队列]

主Agent验收是Canonical Acceptance,不是重新分析漏洞。

通用顺序回退

顺序回退使用与所有子执行器完全相同的task contract。

触发条件:

  • 没有子Agent/Worker能力;
  • 当前宿主没有合格的子执行器;
  • Pi verifier不可执行或缺少http
  • flow超出子执行器的客户端或观察能力;
  • case之间存在冲突;
  • child启动失败;
  • child结果持续不合格;
  • 并行运行中途失效。

回退过程:

flowchart TD
 A[并行路径失效] --> B[保留已验收结果]
 B --> C[未验收active/queued case重新入队]
 C --> D[execution.mode=degraded-sequential]
 D --> E[主Agent逐个读取原task]
 E --> F[按同一Evidence/Result契约执行]
 F --> G[直到全部case终态]

主Agent顺序模式强制检查点:

  1. 读取当前task和target_ref
  2. 把case写为running
  3. 每次交互立即写evidence;
  4. attempt结束更新result;
  5. 得到终态后完成final result;
  6. 更新run.json
  7. 重新读取task、result和evidence;
  8. 验收完成后进入下一case。

不能先执行全部PoC,最后集中补写证据。

4. 单case执行与判定

执行器只关心当前task。

flowchart TD
 A[读取Task] --> B[读取target_ref]
 B --> C[绑定每个step身份]
 C --> D[执行workflow]
 D --> E[保存跨步骤变量]
 E --> F[执行后续step]
 F --> G[检查step assert]
 G --> H[检查最终oracle]
 H --> I{终态?}
 I -->|否且允许调整| J[记录理由并调整PoC]
 J --> D
 I -->|是| K[写Result]

身份处理

匿名步骤必须移除:

  • Cookie;
  • Authorization
  • target.json中配置的全部认证Header。

认证步骤根据identity_id读取凭证。

凭证Header与PoC Header同名冲突时不能静默覆盖,case应为inconclusive并交主Agent处理。

多步骤变量

后续step只能使用前面save产生的变量。Evidence中的variables只记录后续步骤实际复用的值。

不能:

  • 从未执行的步骤构造变量;
  • 根据预期响应猜测变量;
  • 使用另一个case的变量;
  • 把模型推断写成实际提取结果。

HTTP响应是不可信输入

响应正文可以用于:

  • 提取workflow变量;
  • 判断assert;
  • 判断oracle;
  • 决定是否采用task允许的调整。

响应正文不能:

  • 修改task;
  • 指示执行器读取额外文件;
  • 指示执行器调用额外工具;
  • 扩大测试范围;
  • 覆盖系统协议。

Attempt和PoC调整

一次attempt可以包含多次网络交互,但必须全部按顺序保存在同一个evidence文件中。

调整流程:

flowchart TD
 A[执行默认PoC] --> B[写Evidence]
 B --> C[评估Oracle]
 C --> D{满足?}
 D -->|是| E[verified]
 D -->|否| F{存在响应支持的allowed adjustment?}
 F -->|否| G[not_verified或inconclusive]
 F -->|是| H{达到max_attempts?}
 H -->|是| G
 H -->|否| I[记录adjustment_reason]
 I --> J[执行下一attempt]
 J --> B

每次调整都要回答:

  • 上一attempt观察到了什么;
  • 哪个允许调整适用;
  • 为什么这个调整可能影响oracle;
  • 当前是第几次尝试。

不能基于漏洞Reference、通用payload列表或猜测进行无边界试探。

Evidence契约

Evidence回答:所选客户端实际观察到了什么。

每次attempt一个文件:

.auto-verification/evidence/<case-id>-attempt-<n>.json

主要结构:

部分内容
capture实际客户端、执行模式和可见性边界
variables实际复用的跨步骤变量
interactions按序保存的全部实际网络请求
notes工具限制、截断或不可见字段说明

每个interaction包含:

  • sequence
  • workflow step;
  • identity_id
  • 客户端提供时的时间和耗时;
  • 实际传给客户端的请求;
  • 客户端返回的响应;
  • 结构化网络错误。

客户端可见性

Evidence记录的是所选客户端可见事实,不声称是原始TCP/TLS或完整线上HTTP字节流。capture.tool写实际名称,例如httpcurlcapture.modestructured_toolcommand_line

字段记录规则
请求Header只记录显式传给客户端的Header,不补写运行库隐式Header
响应Header记录客户端输出,只声明它实际保留的大小写、顺序和重复字段能力
Redirect记录客户端实际暴露的范围,不虚构中间hop;oracle需要逐跳证据时必须选择支持该能力的客户端
timestamp客户端或宿主不提供时为null
duration_ms客户端或宿主不提供时为nullcurl只有显式采集write-out时间字段时才能使用
错误使用DNS、connect、TLS、timeout、protocol或other类型

Body

内联body支持:

  • utf-8
  • base64

需要记录:

  • 捕获内容;
  • captured_bytes
  • 是否truncated
  • 客户端知道时的original_size_bytes

大响应可以写文件,编码使用file,路径必须位于当前case的evidence prefix。

如果截断部分可能影响oracle,则当前attempt不能据此形成verifiednot_verified。应改用允许的完整证据方式,或者判定为inconclusive

完整信息策略

企业内部验证不对以下内容做额外脱敏:

  • 认证Header;
  • 请求body;
  • 响应body;
  • Result中的请求和观察;
  • 最终报告中的测试凭证和验证细节。

target.json、evidence和报告因此可能包含内部敏感信息,运行目录权限应限制在当前用户。

Result契约

Result回答:Evidence对oracle意味着什么。

每个case一个文件:

.auto-verification/results/<case-id>.json

主要内容:

字段作用
status三态终态
environment目标和实际身份信息
attempts每次目的、请求、调整理由、观察和evidence引用
oracle_checks每条oracle条件是否满足及对应证据
conclusion_basis为什么证据足够或不足
limitations平台、能力或证据限制
infrastructure_issue基础设施阻断
retry用户重试询问和决定

执行器没有可靠时钟时,started_atcompleted_atnull,不能生成看似精确的时间。

三态判定

状态判定标准
verified所有必要oracle满足,且证据足以证明报告声明的影响
not_verified已完成有效验证,但oracle未满足
inconclusive网络、凭证、依赖、前置状态或宿主能力使oracle无法评估

需要始终区分:

  • not_verified不等于漏洞不存在;
  • inconclusive不等于not_verified
  • 静态confirmed不等于动态verified
  • HTTP 200不等于漏洞已验证;
  • 接口接受请求不等于高阶影响已经发生。

Attempt保留

终态保留规则
verifiedResult和最终报告只保留成功attempt
not_verified保留全部有效attempt和调整理由
inconclusive保留已执行attempt、阻断和重试信息

保留策略服务于结论可读性:成功项展示最终可复现路径,未成功项展示完整探索边界,无法判定项展示真实阻断。

Evidence Level

Evidence level来自上游报告,执行阶段不重新选择漏洞影响。

Level需要观察的事实
response响应状态、业务字段、Header或body直接满足判据
differential主探针与对照请求形成稳定差异
time工具真实提供且可重复的时间差
state后续查询观察到状态变化
effect文件、命令、渲染或其他真实效果
cross_identity不同身份之间形成因果和权限边界证据
cross_channel独立HTTP、DNS、消息或其他通道收到关联marker

执行器必须达到task声明的证据等级,不能用更弱观察替代更强影响声明。

5. 汇总与报告

报告前先做集合完整性检查:

flowchart TD
 A[白盒报告ID集合] --> E[集合一致性]
 B[Task ID集合] --> E
 C[Result ID集合] --> E
 D[run.json.cases键集合] --> E
 E --> F{完全相等?}
 F -->|否| G[停止生成报告并修复状态]
 F -->|是| H[检查终态、attempt和evidence]
 H --> I[生成最终报告]

还要确认:

  • 每个ID只有一个终态;
  • attempt_count与Result最终保留attempt一致;
  • Result引用的evidence存在且可解析;
  • result_counts可以从case状态重新计算;
  • 所有inconclusive都有阻断原因;
  • 重试决定只由主Agent记录。

最终报告写在工作区根目录:

VULNERABILITY_VERIFICATION_REPORT.md

不能放在.auto-verification/中。

报告内容:

  • 测试目标和身份;
  • 白盒报告来源;
  • 可达性结果;
  • 三态统计;
  • 全部漏洞汇总;
  • 每个case的最终flow、请求、观察和oracle判断;
  • evidence相对路径;
  • inconclusive阻断和重试决定;
  • 方法和结论边界。

动态结果与白盒静态状态分开呈现,不能相互覆盖。

完成条件

这个SKILL真正完成需要满足:

  • 输入报告契约有效;
  • source hash与当前运行一致;
  • 可达性门禁已处理;
  • 每个漏洞都有一个task;
  • 每个case都有唯一终态;
  • 没有遗留pendingrunning
  • Result和Evidence全部通过验收;
  • ID集合完全一致;
  • 最终报告已经生成;
  • run.json.status=completed
  • report_output指向根目录最终报告。

不能因为某项未验证成功而省略它,也不能把inconclusive排除在总数之外。

agents/openai.yaml

这个文件只负责界面层:

字段内容
display_name自动漏洞验证
short_description按单case验证白盒漏洞并汇总生成报告
default_prompt根据白盒漏洞报告验证测试站点并生成验证报告

真正的workflow、策略和Agent协议分别位于SKILL.mdcontext-schema.mdvulnerability-verifier.md

设计取舍

主Agent编译task,执行器不读报告

主Agent本来就负责:

  • 校验完整报告;
  • 解析身份需求;
  • 选择variant;
  • 汇总所有结果。

让它逐case编译task不会增加新的业务职责。编译完成后,执行阶段只需要读取task和Artifact,避免把完整报告反复注入每个child。

Task引用凭证,不复制凭证

凭证集中保存在target.json,task只保存target_ref和身份ID。

这样可以:

  • 更新凭证而不重写全部task;
  • 避免同一凭证在并发任务中重复出现;
  • 保持身份绑定稳定。

Evidence和报告仍按企业内网策略保存实际认证信息。

子Agent保持薄

单case执行器只拥有当前case需要的工具和角色协议;Pi的首选实现是薄vulnerability-verifier

如果把编译、调度、报告或漏洞知识加入agent,它就会与SKILL重复,并破坏单case执行器边界。

不给执行器漏洞Reference

References对漏洞发现有价值,但对执行已编译flow没有必要。执行器只需要知道:

  • 发什么;
  • 使用哪个身份;
  • 保存什么变量;
  • 如何判定;
  • 失败后允许怎么调整。

子Agent只是加速层

主Agent拥有完整顺序执行能力,因此并行插件失败不会改变验证语义和最终完整性。

一个case一个task

这个粒度使:

  • 所有权清晰;
  • 写入范围明确;
  • 恢复简单;
  • Result可独立验收;
  • 冲突容易声明;
  • 主Agent和子Agent可以共用协议。

主Agent唯一写全局状态

牺牲并行写run.json的便利,换取:

  • 无Lost Update;
  • 计数一致;
  • 恢复点唯一;
  • 重试决定集中;
  • 最终报告稳定。

Evidence只记录客户端可见事实

不要求客户端无法提供的原始报文、重定向hop或精确时间,可以避免为了满足schema而编造证据;但在另一现有客户端可以提供oracle所需事实时,应先切换客户端,而不是直接降级结论。

破坏性与脱敏策略由环境决定

当前企业测试内网有快速快照恢复能力,因此允许task中的破坏性PoC,并保留完整验证信息。真正需要约束的是执行范围,而不是用通用“低影响”规则覆盖本地授权模型。

维护风险

verification_handoff耦合

这个SKILL依赖上游白盒报告字段:

  • report.schema_versionverification_handoff.schema_version
  • identity_requirements
  • required_capabilities
  • workflow;
  • variants;
  • oracle;
  • evidence level;
  • negative control;
  • allowed_adjustments
  • 旧报告中的alternatives兼容输入。

这些字段变化需要同步修改:

  • task compiler规则;
  • context-schema.md
  • Result验收;
  • 最终报告模板;
  • 设计笔记。

应按Schema Migration处理,而不是只改文案。

通用宿主适配变化

调度协议不能绑定某个宿主的工具名或子Agent API。宿主升级时重新发现:

  • 是否能创建隔离的单case执行器;
  • 子执行器的最小文件与网络能力;
  • 主Agent是否可以完整顺序回退;
  • 结构化HTTP工具与命令行客户端的真实可用性;
  • 并发上限、完成通知和运行引用。

只要task、result和evidence契约不变,宿主适配器可以替换;不能把Pi专有字段提升为通用协议必填项。

Pi pi-subagents API变化

Agent发现和调度必须以当前会话实际暴露的schema为准。

维护时优先检查:

  • agent list;
  • executable状态;
  • fresh context;
  • async或并发调用;
  • run reference;
  • wait或完成通知;
  • diagnostics。

不要把某个版本的调用示例固化为永远不变的API。

@evalexp/pi-http能力变化

如果HTTP扩展新增或修改:

  • Header输入模型;
  • Redirect行为;
  • 时间字段;
  • 响应大小限制;
  • downloadPath
  • 文件上传;
  • TLS选项;

必须同步检查evidence契约和Pi verifier可调度case范围。该扩展是Pi首选结构化客户端,不是SKILL运行前提;升级或缺失都不能移除curl及其他已有客户端的通用回退路径。

Agent工具继承语义

Pi专用verifier依赖:

  • 主profile加载@evalexp/pi-http
  • agent不声明extensions
  • toolsallowlist选择已经注册的http工具。

Pi或pi-subagents升级后,需要重新执行实际agent discovery,不能只解析Markdown推断。其他宿主不需要实现这些Pi字段,只需满足单case任务和读写边界。

完整信息保存

当前策略不脱敏Evidence、Result和Report。维护时不能擅自加入通用脱敏逻辑,但应保持:

  • target.json尽可能使用0600
  • 运行目录仅对当前用户可读;
  • 最终报告的存放位置符合企业内部使用边界。

Snapshot恢复假设

Skill不设计cleanup,依赖外部快照恢复。

如果未来运行环境不再提供快照,需要重新设计:

  • cleanup字段;
  • 可逆性;
  • 环境重置检查点;
  • 并发隔离。

不能只删除“快照”文案而保留当前副作用模型。

Verified历史保留

当前verified只保留成功attempt。如果以后需要完整研究轨迹,应明确区分:

  • 机器运行日志;
  • Canonical Result;
  • 最终报告展示。

不能简单改变attempt retention而不调整attempt_count和报告语义。

后续增强方向

后续增强优先考虑:

  1. context-schema增加显式迁移规则;
  2. 在出现真实重复错误后增加确定性JSON validator;
  3. 给不同执行能力定义清晰的executor capability描述;
  4. 为Callback、Browser、WebSocket和Race case定义独立但兼容的执行后端;
  5. 增加中断恢复的隔离前向测试;
  6. 增加子Agent失败后顺序回退的行为测试;
  7. 验证大响应下载、截断和oracle关系;
  8. 为资源声明建立更稳定的key约定。

不优先增加:

  • 漏洞知识库;
  • 漏洞类型Reference;
  • 通用payload大全;
  • 让执行器自行发现攻击路径。

这些属于上游漏洞挖掘或审计阶段。

修改时需要保持的核心约束

以后修改这个SKILL时,至少保持:

  • verification_handoff是唯一执行模型;
  • 不从漏洞描述重新设计攻击路径;
  • 一个case一个task;
  • variant由主Agent选择;
  • task不复制凭证;
  • task不包含漏洞Reference;
  • 子执行器一次只执行一个case,并使用宿主等价的隔离上下文;
  • 核心task、result和evidence契约不依赖Pi、固定agent名或固定HTTP工具;
  • 结构化HTTP工具优先,不能表达时回退到已有curl或等价命令行客户端;
  • 客户端不可用或能力不足时先检查其他执行器和主Agent路径,不能直接漏掉case;
  • Pi verifier使用fresh context,不继承Project、Global或Skill上下文;
  • Pi verifier工具只包含readwritehttp,且不重复声明extensions
  • 最多3个无冲突的单case执行器;
  • 主Agent是run.json和最终报告唯一写入者;
  • 子Agent失败必须回退顺序模式;
  • 子Agent失败不能成为漏洞结论;
  • 主Agent回退使用同一个task contract;
  • 每次网络交互立即写Evidence;
  • 写入顺序为Evidence → Result → run.json
  • Evidence记录实际客户端和真实可见事实;
  • 客户端不可见字段不能推断;
  • 匿名步骤必须移除全部认证Header;
  • 跨身份结论必须有真实不同身份和基线;
  • PoC调整只能来自allowed_adjustments和实际响应;
  • 达到max_attempts必须停止;
  • 允许task内破坏性PoC;
  • Evidence、Result和Report保留完整信息;
  • 不引入task外动作或扩大执行范围;
  • cleanup依赖外部快照,不由执行器设计;
  • 所有case必须有唯一三态终态;
  • not_verified不能表述为漏洞不存在;
  • source hash变化不能复用旧结果;
  • Final Report只消费已验收Result并引用Evidence。

快速定位

问题先看
整体workflowSKILL.md
运行状态不一致references/context-schema.md中的run.json
身份或凭证问题target.json契约
Task编译错误references/context-schema.md中的tasks/<case-id>.json
Child读取了额外上下文当前宿主的单case隔离配置;Pi看profile_sys/agents/vulnerability-verifier.md
HTTP客户端选择错误SKILL.md中的“宿主与HTTP客户端适配”及run.json.execution.http_clients
Pi verifier没有httpAgent的tools与主profile扩展加载状态;不可用时走通用回退
Child没有被发现当前宿主实际worker discovery;Pi看pi-subagents的agent list与diagnostics
并发状态冲突parallel_saferesource_claims
中断后是否可以重放side_effectreplay
Evidence缺字段客户端可见性和capture.tool/mode规则
大响应被截断所选客户端的下载能力和evidence body规则
Oracle判断不充分Result中的oracle_checks与Evidence引用
Child结果不可信主AgentResult验收流程
子Agent失败后case丢失execution.mode与顺序回退队列
三态计数不一致run.json.casesresult_counts
最终报告格式assets/VERIFICATION_REPORT_TEMPLATE.md
报告遗漏case报告、task、result和run.json.cases的ID集合检查
输入报告发生变化source.sha256恢复门禁