关于 zeroize-audit
用于检查 C、C++ 和 Rust 代码中敏感数据未清零或清零操作被编译器移除的安全审计技能。它结合源码与数据流分析、LLVM IR 和汇编证据,并生成结构化报告。
主要功能
- 01审计敏感数据清零
- 02分析 C、C++ 和 Rust
- 03检查 LLVM IR 与汇编
- 04追踪秘密数据副本
- 05生成 PoC 和报告
适用场景
- 01审计加密密钥清理
- 02检查密码和令牌处理
- 03验证清零操作未被优化
- 04检查敏感数据错误路径
MCP 相关
该技能可通过 Serena MCP 执行语义查询;配置项可将 MCP 设为关闭、优先使用或必需。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ trailofbits/ skills --skill zeroize-audit安装后在 Claude Code 中输入/zeroize-audit确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlassets/trail-of-bits-mark.svgconfigs/c.yamldefault.yamlrust.yamlprompts/report_template.mdsystem.mdtask.mdreferences/compile-commands.mddetection-strategy.mdir-analysis.mdmcp-analysis.mdpoc-generation.mdrust-zeroization-patterns.mdschemas/input.jsonoutput.jsontools/analyze_asm.shanalyze_cfg.pyanalyze_heap.shanalyze_ir_semantic.pydiff_ir.shdiff_rust_mir.shemit_asm.shemit_ir.shemit_rust_asm.shemit_rust_ir.shemit_rust_mir.shextract_compile_flags.pygenerate_poc.pytools/mcp/apply_confidence_gates.py详细介绍
zeroize-audit
适用场景
- 审计密码学实现(密钥、种子、随机数、机密信息)
- 审查身份验证系统(密码、令牌、会话数据)
- 分析处理个人身份信息(PII)或敏感凭据的代码
- 验证安全关键代码库中的安全清理操作
- 调查敏感数据处理的内存安全性
不适用场景
- 不以安全为重点的一般代码审查
- 性能优化(与安全擦除相关的情况除外)
- 与敏感数据无关的重构任务
- 不包含可识别机密信息或敏感值的代码
执行约定
使用 Agent 环境提供的工具访问文件、运行 shell 命令、执行工作任务和获取用户输入。allowed-tools 条目和角色文件的 frontmatter 是旧版宿主元数据;它们不会定义其他环境的工具名称,也不会在其他环境中授予权限。
- 解析资源。 将
baseDir设为包含此SKILL.md的绝对目录。确认链接的输入架构和编排器提示词在该目录中存在。{baseDir}、{workdir}和{{input}}是需要由编排器替换的值的表示形式,并非环境变量,也不会由宿主自动展开。相对 Markdown 链接应相对于其所在文件的目录解析;{baseDir}/…路径应相对于技能目录解析。将解析后的路径传递给工作器和 shell 命令。 - 启动角色。 阅读 Agent 架构表中链接的角色提示词。如果环境中已注册该角色的工作器,请使用其
zeroize-audit:<role-name>标识符(例如zeroize-audit:0-preflight);否则,使用该提示词的 Markdown 正文、当前阶段的说明及其参数值创建一个独立工作器。始终包含解析后的baseDir,并在创建后包含workdir,即使阶段表中未重复提及。委派前,按照上述规则解析资源引用。工作器的文件、搜索和 shell 操作使用环境实际提供的工具架构和权限。角色名称标识其指令,不代表必须使用特定的调度 API 或模型。 - 等待结果。 保留每个工作器的句柄,并通过环境提供的完成机制等待。启动确认不代表任务已完成。读取阶段要求的产物后,才能更新其完成状态或启动依赖阶段。如果工作器执行失败或无法调度,只应用该阶段文档中规定的回退方案;否则,在现有运行状态中记录失败,并报告受影响的阶段已阻塞。
- 并发。 遵守可用的并发限制和阶段屏障。无法并行执行时,按顺序运行工作器。每个翻译单元(TU)的编译工作器应写入不同目录,因此可以并发运行。
- 收集决策。 使用环境的用户输入功能,或直接在对话中提问。阶段需要用户作答时,应等待答复;不要用默认值或经过的时间代替用户决策。记录任何已接受或已拒绝的 PoC 结果时,应保留其验证和核验结果。
运行方法
对于“审计此 crate,检查是否有秘密数据残留在内存中”或“检查此 C 库是否确实清除了密钥”这类请求:
- 收集输入。 将请求映射到下方的 Inputs 表(完整架构:schemas/input.json)。
path为必填项,此外还必须提供compile_db(C/C++)或cargo_manifest(Rust)中的至少一项;如果两者都未提供,且无法从仓库推导得出,则向用户询问,因为没有其中一项时,预检会停止运行。除非用户另有说明,否则其他字段均保留默认值。 - 阅读编排器提示词,并将收集到的输入填入其中的
{{placeholder}}值。你要扮演其中描述的编排器:它定义了状态恢复、阶段循环、提前终止和错误处理。还要一并阅读共享指令,了解所有阶段都依赖的共享工作目录布局和 Agent 错误协议。 - 执行阶段循环。 按顺序运行阶段 0-7。每个阶段开始前,阅读
{baseDir}/workflows/phase-{N}-{name}.md中该阶段的工作流文件,并遵循其中的 Preconditions、Instructions、State Update 和 Error Handling 部分。每个工作流都会指定上述执行约定中要使用的角色提示词和参数。遵循每个阶段的跳过条件以及 task.md 中的提前终止规则。 - 返回报告(阶段 8,内联):阅读
{workdir}/report/final-report.md并将其内容作为技能输出返回。
恢复中断的运行:如果此前的上下文中已知 workdir,则阅读 {workdir}/orchestrator-state.json,并从其中的 current_phase 继续,而不是从阶段 0 开始(参见 task.md 的 Recovery 部分)。
目的
检测源代码中敏感数据未被清零的情况,并找出被编译器优化(例如死存储消除)移除或弱化的清零操作,同时必须提供 LLVM IR/汇编证据。功能包括:
- 汇编级分析寄存器溢出和栈上残留
- 追踪数据流中的秘密数据副本
- 发出堆分配器安全警告
- 进行语义 IR 分析,检查循环展开和 SSA 形式
- 分析控制流图以验证路径覆盖情况
- 生成运行时验证测试
范围
- 以只读方式访问目标代码库(不会修改已审计代码;会将分析产物写入临时工作目录)。
- 生成结构化报告(JSON)。
- 需要有效的构建上下文(
compile_commands.json)和可编译的翻译单元。 - 只有提供编译器证据(IR/汇编差异),才允许报告“已被优化掉”的发现。
输入
完整架构请参见 schemas/input.json。关键字段:
| 字段 | 必填 | 默认值 | 描述 |
|---|---|---|---|
path | 是 | — | 仓库根目录 |
compile_db | 否 | null | 用于 C/C++ 分析的 compile_commands.json 路径。如果未设置 cargo_manifest,则为必填项。 |
cargo_manifest | 否 | null | 用于 Rust crate 分析的 Cargo.toml 路径。如果未设置 compile_db,则为必填项。 |
config | 否 | — | 定义启发式规则和已批准擦除操作的 YAML |
opt_levels | 否 | ["O0","O1","O2"] | 用于 IR 比较的优化级别。O1 是诊断级别:如果擦除操作在 O1 下消失,则属于简单的 DSE;O2 可检测更激进的消除。 |
languages | 否 | ["c","cpp","rust"] | 要分析的语言 |
max_tus | 否 | 50 | 限制从编译数据库处理的翻译单元数量 |
mcp_mode | 否 | prefer | off、prefer 或 require — 控制 Serena MCP 的使用 |
mcp_required_for_advanced | 否 | true | 当 MCP 不可用时,将 SECRET_COPY、MISSING_ON_ERROR_PATH 和 NOT_DOMINATING_EXITS 降级为 needs_review |
mcp_timeout_ms | 否 | 10000 | MCP 语义查询的超时预算 |
poc_categories | 否 | 全部 11 种可利用类别 | 要生成 PoC 的发现类别。C/C++ 发现:支持全部 11 种类别。Rust 发现:仅支持 MISSING_SOURCE_ZEROIZE、SECRET_COPY 和 PARTIAL_WIPE;其他 Rust 类别标记为 poc_supported=false。 |
poc_output_dir | 否 | generated_pocs/ | 生成的 PoC 的输出目录 |
enable_asm | 否 | true | 启用汇编生成和分析(步骤 8);会产生 STACK_RETENTION、REGISTER_SPILL。如果缺少 emit_asm.sh,则自动禁用。 |
enable_semantic_ir | 否 | false | 启用语义 LLVM IR 分析(步骤 9);会产生 LOOP_UNROLLED_INCOMPLETE |
enable_cfg | 否 | false | 启用控制流图分析(步骤 10);会产生 MISSING_ON_ERROR_PATH、NOT_DOMINATING_EXITS |
enable_runtime_tests | 否 | false | 启用运行时测试框架生成(步骤 11) |
前置条件
运行前,请确认以下各项。每项都定义了对应的失败处理方式。
C/C++ 前置条件:
| 前置条件 | 缺少时的失败处理方式 |
|---|---|
compile_db 路径下的 compile_commands.json | 立即失败 — 不要继续 |
PATH 中有 clang | 立即失败 — 无法进行 IR/ASM 分析 |
PATH 中有 uvx(用于 Serena) | 如果 mcp_mode=require:失败。如果 mcp_mode=prefer:在不使用 MCP 的情况下继续;根据置信度门控规则降低受影响发现的置信度。 |
{baseDir}/tools/extract_compile_flags.py | 立即失败 — 无法提取每个 TU 的标志 |
{baseDir}/tools/emit_ir.sh | 立即失败 — 无法进行 IR 分析 |
{baseDir}/tools/emit_asm.sh | 发出警告并跳过汇编发现(STACK_RETENTION、REGISTER_SPILL) |
{baseDir}/tools/mcp/check_mcp.sh | 发出警告并将 MCP 视为不可用 |
{baseDir}/tools/mcp/normalize_mcp_evidence.py | 发出警告并使用原始 MCP 输出 |
Rust 前置条件:
| 前置条件 | 缺少时的失败处理方式 |
|---|---|
cargo_manifest 路径下的 Cargo.toml | 立即失败 — 不要继续 |
cargo check 通过 | 立即失败 — crate 必须可构建 |
PATH 中有 cargo +nightly | 立即失败 — MIR 和 LLVM IR 输出需要 nightly |
PATH 中有 uv | 立即失败 — 运行 Python 分析脚本所必需 |
{baseDir}/tools/validate_rust_toolchain.sh | 发出警告 — 手动运行预检。检查所有工具、脚本、nightly,以及可选的 cargo check。使用 --json 获取机器可读的输出,使用 --manifest 还可验证 crate 是否能构建。 |
{baseDir}/tools/emit_rust_mir.sh | 立即失败 — 无法进行 MIR 分析(支持 --opt、--crate、--bin/--lib;--out 可以是文件或目录) |
{baseDir}/tools/emit_rust_ir.sh | 立即失败 — 无法进行 LLVM IR 分析(必须指定 --opt;支持 --crate、--bin/--lib;--out 必须是 .ll) |
{baseDir}/tools/emit_rust_asm.sh | 发出警告并跳过汇编发现(STACK_RETENTION、REGISTER_SPILL)。支持 --opt、--crate、--bin/--lib、--target、--intel-syntax;--out 可以是 .s 文件或目录。 |
{baseDir}/tools/diff_rust_mir.sh | 发出警告并跳过 MIR 级别的优化比较。接受 2 个或更多 MIR 文件,进行规范化、两两比较,并报告零化/析构胶水模式消失时的首个优化级别。 |
{baseDir}/tools/scripts/semantic_audit.py | 发出警告并跳过语义源代码分析 |
{baseDir}/tools/scripts/find_dangerous_apis.py | 发出警告并跳过危险 API 扫描 |
{baseDir}/tools/scripts/check_mir_patterns.py | 发出警告并跳过 MIR 分析 |
{baseDir}/tools/scripts/check_llvm_patterns.py | 发出警告并跳过 LLVM IR 分析 |
{baseDir}/tools/scripts/check_rust_asm.py | 发出警告并跳过 Rust 汇编分析(STACK_RETENTION、REGISTER_SPILL、析构胶水检查)。分派至 check_rust_asm_x86.py(生产版)或 check_rust_asm_aarch64.py(实验性 — AArch64 发现需要手动验证)。 |
{baseDir}/tools/scripts/check_rust_asm_x86.py | check_rust_asm.py 进行 x86-64 分析所必需;如果缺少则发出警告并跳过 |
{baseDir}/tools/scripts/check_rust_asm_aarch64.py | check_rust_asm.py 进行 AArch64 分析所必需(实验性);如果缺少则发出警告并跳过 |
通用前置条件:
| 前置条件 | 缺少时的失败处理方式 |
|---|---|
{baseDir}/tools/generate_poc.py | 立即失败 — 必须生成 PoC |
已批准的擦除 API
以下 API 会被识别为有效的零化方式。可在 {baseDir}/configs/ 中配置其他条目。
C/C++
explicit_bzeromemset_sSecureZeroMemoryOPENSSL_cleansesodium_memzero- 易失擦除循环(基于模式;参见
{baseDir}/configs/default.yaml中的volatile_wipe_patterns) - 在 IR 中:带易失标志的
llvm.memset、易失存储,或不可消除的擦除调用
Rust
zeroize::Zeroizetrait(zeroize()方法)Zeroizing<T>封装(基于 drop)ZeroizeOnDrop派生宏
发现的问题
发现的问题按所需证据分组。仅尝试检查具备所需工具支持的问题。
| 发现 ID | 描述 | 要求 | PoC 支持 |
|---|---|---|---|
MISSING_SOURCE_ZEROIZE | 未在源代码中发现清零操作 | 仅源代码 | 是(C/C++ + Rust) |
PARTIAL_WIPE | 清零大小不正确或清零不完整 | 仅源代码 | 是(C/C++ + Rust) |
NOT_ON_ALL_PATHS | 某些控制流路径上缺少清零操作(启发式判断) | 仅源代码 | 是(仅 C/C++) |
SECRET_COPY | 复制敏感数据时未跟踪清零操作 | 源代码 + MCP(优先) | 是(C/C++ + Rust) |
INSECURE_HEAP_ALLOC | 秘密使用了不安全的分配器(malloc 而非 secure_malloc) | 仅源代码 | 是(仅 C/C++) |
OPTIMIZED_AWAY_ZEROIZE | 编译器移除了清零操作 | 需要 IR diff(不能仅依赖源代码) | 是 |
STACK_RETENTION | 函数返回后,栈帧可能仍保留秘密 | 需要汇编(C/C++);需要 LLVM IR alloca+lifetime.end 证据(Rust);汇编佐证可将状态升级为 confirmed | 是(仅 C/C++) |
REGISTER_SPILL | 秘密从寄存器溢出到栈 | 需要汇编(C/C++);需要 LLVM IR load+调用点证据(Rust);汇编佐证可将状态升级为 confirmed | 是(仅 C/C++) |
MISSING_ON_ERROR_PATH | 错误处理路径缺少清理操作 | 需要 CFG 或 MCP | 是 |
NOT_DOMINATING_EXITS | 清零操作未支配所有退出路径 | 需要 CFG 或 MCP | 是 |
LOOP_UNROLLED_INCOMPLETE | 展开的循环中清零不完整 | 需要语义 IR | 是 |
Agent 架构
分析流水线在 8 个阶段中使用 11 种工作角色,由编排器按照上述执行约定启动。Agent 会将持久化的发现文件写入共享工作目录(/tmp/zeroize-audit-{run_id}/),从而支持并行执行并减轻上下文压力。
| Agent | 阶段 | 用途 | 输出目录 |
|---|---|---|---|
| 0-preflight | 阶段 0 | 执行预检(工具、工具链、编译数据库、crate 构建)、合并配置、创建工作目录、枚举 TU | {workdir}/ |
| 1-mcp-resolver | 阶段 1,波次 1(仅限 C/C++) | 通过 Serena MCP 解析符号、类型和跨文件引用 | mcp-evidence/ |
| 2-source-analyzer | 阶段 1,波次 2a(仅限 C/C++) | 识别敏感对象、检测擦除操作、验证正确性、分析数据流/堆 | source-analysis/ |
| 2b-rust-source-analyzer | 阶段 1,波次 2b(仅限 Rust,与 2a 并行) | 基于 Rustdoc JSON 和 trait 的分析 + 危险 API grep | source-analysis/ |
| 3-tu-compiler-analyzer | 阶段 2,波次 3(仅限 C/C++,N 个并行任务) | 逐个 TU 分析 IR 差异、汇编、语义 IR 和 CFG | compiler-analysis/{tu_hash}/ |
| 3b-rust-compiler-analyzer | 阶段 2,波次 3R(仅限 Rust,单个 Agent) | 分析 crate 级 MIR、LLVM IR 和汇编 | rust-compiler-analysis/ |
| 4-report-assembler | 阶段 3(中期)+ 阶段 6(最终) | 收集所有 Agent 的发现、应用置信度门槛;合并 PoC 结果并生成最终报告 | report/ |
| 5-poc-generator | 阶段 4 | 编写专用的概念验证程序(C/C++:所有类别;Rust:MISSING_SOURCE_ZEROIZE、SECRET_COPY、PARTIAL_WIPE) | poc/ |
| 5b-poc-validator | 阶段 5 | 编译并运行所有 PoC | poc/ |
| 5c-poc-verifier | 阶段 5 | 验证每个 PoC 是否证明了其声称的发现 | poc/ |
| 6-test-generator | 阶段 7(可选) | 生成运行时验证测试框架 | tests/ |
编排器每次从 {baseDir}/workflows/ 读取一个阶段工作流文件,并维护 orchestrator-state.json,以便在上下文压缩后恢复。Agent 通过文件路径(config_path)而非配置值接收配置。
执行流程
Phase 0: 0-preflight agent — Preflight + config + create workdir + enumerate TUs
→ writes orchestrator-state.json, merged-config.yaml, preflight.json
Phase 1: Wave 1: 1-mcp-resolver (skip if mcp_mode=off OR language_mode=rust)
Wave 2a: 2-source-analyzer (C/C++ only; skip if no compile_db) ─┐ parallel
Wave 2b: 2b-rust-source-analyzer (Rust only; skip if no cargo_manifest) ─┘
Phase 2: Wave 3: 3-tu-compiler-analyzer x N (C/C++ only; parallel per TU)
Wave 3R: 3b-rust-compiler-analyzer (Rust only; single crate-level agent)
Phase 3: Wave 4: 4-report-assembler (mode=interim → findings.json; reads all agent outputs)
Phase 4: Wave 5: 5-poc-generator (C/C++: all categories; Rust: MISSING_SOURCE_ZEROIZE, SECRET_COPY, PARTIAL_WIPE; other Rust findings: poc_supported=false)
Phase 5: PoC Validation & Verification
Step 1: 5b-poc-validator agent (compile and run all PoCs)
Step 2: 5c-poc-verifier agent (verify each PoC proves its claimed finding)
Step 3: Orchestrator asks the user to accept or reject failed verification
Step 4: Orchestrator merges all results into poc_final_results.json
Phase 6: Wave 6: 4-report-assembler (mode=final → merge PoC results, final-report.md)
Phase 7: Wave 7: 6-test-generator (optional)
Phase 8: Orchestrator — Return final-report.md
交叉引用约定
ID 按 Agent 进行命名空间划分,以避免并行执行期间发生冲突:
| 实体 | 模式 | 分配者 |
|---|---|---|
| 敏感对象(C/C++) | SO-0001–SO-4999 | 2-source-analyzer |
| 敏感对象(Rust) | SO-5000–SO-9999(Rust 命名空间) | 2b-rust-source-analyzer |
| 源码发现(C/C++) | F-SRC-NNNN | 2-source-analyzer |
| 源码发现(Rust) | F-RUST-SRC-NNNN | 2b-rust-source-analyzer |
| IR 发现(C/C++) | F-IR-{tu_hash}-NNNN | 3-tu-compiler-analyzer |
| ASM 发现(C/C++) | F-ASM-{tu_hash}-NNNN | 3-tu-compiler-analyzer |
| CFG 发现 | F-CFG-{tu_hash}-NNNN | 3-tu-compiler-analyzer |
| 语义 IR 发现 | F-SIR-{tu_hash}-NNNN | 3-tu-compiler-analyzer |
| Rust MIR 发现 | F-RUST-MIR-NNNN | 3b-rust-compiler-analyzer |
| Rust LLVM IR 发现 | F-RUST-IR-NNNN | 3b-rust-compiler-analyzer |
| Rust 汇编发现 | F-RUST-ASM-NNNN | 3b-rust-compiler-analyzer |
| 翻译单元 | TU-{hash} | 编排器 |
| 最终发现 | ZA-NNNN | 4-report-assembler |
每个发现 JSON 对象都包含 related_objects、related_findings 和 evidence_files 字段,用于 Agent 之间的交叉引用。
检测策略
分析分两个阶段进行。有关完整的分步指南,请参阅 {baseDir}/references/detection-strategy.md。
| 阶段 | 步骤 | 产生的发现 | 所需工具 |
|---|---|---|---|
| 阶段 1(源码) | 1–6 | MISSING_SOURCE_ZEROIZE、PARTIAL_WIPE、NOT_ON_ALL_PATHS、SECRET_COPY、INSECURE_HEAP_ALLOC | 源码 + 编译数据库 |
| 阶段 2(编译器) | 7–12 | OPTIMIZED_AWAY_ZEROIZE、STACK_RETENTION、REGISTER_SPILL、LOOP_UNROLLED_INCOMPLETE†、MISSING_ON_ERROR_PATH‡、NOT_DOMINATING_EXITS‡ | clang、IR/ASM 工具 |
* 需要 enable_asm=true(默认值)
† 需要 enable_semantic_ir=true
‡ 需要 enable_cfg=true
对于 Rust,{baseDir}/references/rust-zeroization-patterns.md 收录了 40 种命名的反模式,并注明检测每种模式的脚本:A 节对应 rustdoc-JSON 语义(semantic_audit.py),B 节对应危险 API(find_dangerous_apis.py),C 节对应 MIR/LLVM IR/汇编(check_mir_patterns.py、check_llvm_patterns.py、check_rust_asm.py)。对 Rust 发现进行分类、撰写修复建议,或判断手动发现的模式是否已有覆盖时,请阅读相关章节。
该参考资料的覆盖范围有两点限制。A–C 节中的 34 项是脚本当前能够检测的内容;D 节中的 6 项是没有脚本覆盖的已知缺口,因此应视为未经审计,而非没有问题。A 节和 C 节也并未完全覆盖——脚本会输出一些没有对应条目的类别,因此,即使某项发现与目录中的模式都不匹配,它仍然是一个发现,应保留脚本提供的所有证据。
输出格式
每次运行会生成两个输出:
final-report.md—— 综合 Markdown 报告(主要的可读输出)findings.json—— 符合{baseDir}/schemas/output.json规范的结构化 JSON(供机器和下游工具使用)
Markdown 报告结构
Markdown 报告(final-report.md)包含以下部分:
- 标题:运行元数据(run_id、timestamp、repo、compile_db、配置摘要)
- 执行摘要:按严重性、置信度和类别统计发现数量
- 敏感对象清单:包含所有已识别对象及其 ID、类型和位置的表格
- 发现:按严重性、再按置信度分组。每项发现均包含位置、对象、所有证据(源码/IR/ASM/CFG)、编译器证据详情和建议的修复方法
- 已取代的发现:由 CFG 支持的发现取代的源码发现
- 置信度门控摘要:已应用的降级和被拒绝的覆盖
- 分析覆盖范围:已分析的 TUs、Agent 的成功/失败情况、已启用的功能,以及该 crate 使用但没有脚本审计的任何 D 节模式
- 附录:证据文件:发现 ID 到证据文件路径的映射
结构化 JSON
findings.json 文件遵循 {baseDir}/schemas/output.json 中的规范。每个 Finding 对象:
{
"id": "ZA-0001",
"category": "OPTIMIZED_AWAY_ZEROIZE",
"severity": "high",
"confidence": "confirmed",
"language": "c",
"file": "src/crypto.c",
"line": 42,
"symbol": "key_buf",
"evidence": "store volatile i8 0 count: O0=32, O2=0 — wipe eliminated by DSE",
"compiler_evidence": {
"opt_levels": ["O0", "O2"],
"o0": "32 volatile stores targeting key_buf",
"o2": "0 volatile stores (all eliminated)",
"diff_summary": "All volatile wipe stores removed at O2 — classic DSE pattern"
},
"suggested_fix": "Replace memset with explicit_bzero or add compiler_fence(SeqCst) after the wipe",
"poc": {
"file": "generated_pocs/ZA-0001.c",
"makefile_target": "ZA-0001",
"compile_opt": "-O2",
"requires_manual_adjustment": false,
"validated": true,
"validation_result": "exploitable"
}
}
完整规范和枚举值请参阅 {baseDir}/schemas/output.json。
置信度门控
证据阈值
一项发现至少需要 2 个独立信号 才能标记为 confirmed。有 1 个信号时标记为 likely。没有强信号(仅匹配名称模式)时标记为 needs_review。
信号包括:名称模式匹配、类型提示匹配、显式注解、IR 证据、ASM 证据、MCP 交叉引用、CFG 证据、PoC 验证。
将 PoC 验证作为证据依据
每项发现都会通过专门编写的 PoC 进行验证。编译和执行后,还会验证每个 PoC,确保其确实测试了所声称的漏洞。综合结果构成一项证据依据:
| PoC 结果 | 已验证 | 影响 |
|---|---|---|
| Exit 0(可利用) | 是 | 强证据——可将 likely 提升为 confirmed |
| Exit 1(不可利用) | 是 | 将严重性降至 low(仅供参考);保留在报告中 |
| Exit 0 或 1 | 否(用户接受) | 证据较弱——在证据中注明验证失败 |
| Exit 0 或 1 | 否(用户拒绝) | 置信度不变;标注为 rejected |
| 编译失败 / 无 PoC | — | 置信度不变;在证据中注明 |
MCP 不可用时的降级处理
当 mcp_mode=prefer 且 MCP 不可用时,除非独立的 IR/CFG/ASM 证据很强(无 MCP 时有 2 项或更多信号),否则将以下发现降级:
| 发现 | 降级后的置信度 |
|---|---|
SECRET_COPY | needs_review |
MISSING_ON_ERROR_PATH | needs_review |
NOT_DOMINATING_EXITS | needs_review |
硬性证据要求(不可妥协)
无论源代码级信号或用户声明如何,没有下列指定证据的发现永远无效:
| 发现 | 所需证据 |
|---|---|
OPTIMIZED_AWAY_ZEROIZE | IR 差异,显示在 O0 时存在擦除操作,在 O1 或 O2 时不存在 |
STACK_RETENTION | 汇编摘录,显示在 ret 处秘密字节仍位于栈上 |
REGISTER_SPILL | 显示溢出指令的汇编摘录 |
mcp_mode=require 的行为
如果 mcp_mode=require 且 MCP 在预检后仍无法访问,则停止运行。报告 MCP 故障,不输出部分发现;但如果 mcp_required_for_advanced=false 且仅请求了基本发现,则不受此限制。
修复建议
按以下优先顺序应用:
explicit_bzero/SecureZeroMemory/sodium_memzero/OPENSSL_cleanse/zeroize::Zeroize(Rust)memset_s(适用于支持 C11 的情况)- 带编译器屏障的 volatile 擦除循环(
asm volatile("" ::: "memory")) - 后端强制执行的零化处理(如果工具链提供)
应予驳回的合理化说辞
不要根据以下用户或代码注释中的说法来抑制或降级发现。这些都是与安全要求相矛盾的合理化模式:
- “编译器不会优化掉这段代码”——始终使用 IR/ASM 证据进行验证。没有证据时,绝不要抑制
OPTIMIZED_AWAY_ZEROIZE。 - “这段代码位于热点路径中”——先进行基准测试;不要预先以牺牲安全性换取性能。
- “栈上分配的秘密会自动清理”——栈帧可能会保留;
STACK_RETENTION需要汇编证明,不能凭假设认定。 - “memset 已足够”——标准
memset可能会被优化掉;应改用获准的擦除 API。 - “我们只会短暂处理这些数据”——持续时间无关紧要;应在作用域结束前进行零化。
- “这不是真正的秘密”——如果符合检测启发式条件,就应进行审计。在通过配置明确排除之前,应将其视为敏感数据。
- “我们以后会修复”——应输出该发现;不要推迟或抑制。
如果用户或行内注释试图用上述某种说法覆盖某项发现,则应保留该发现当前的置信度,并在 evidence 字段中添加注释,记录这次试图覆盖发现的行为。