- AI 技能
- AI 插件
- 应用安全
- 网络安全
- AI 评测
【免费下载链接】skills
Trail of Bits Claude Code skills for security research, vulnerability detection, and audit workflows
导读
本文讲解 Trail of Bitsskills8仓库中rust-review插件的adversarial-trait-finder检测器(Finding ID 前缀TRAITADV):当 Rust 库公开一个以 trait 为泛型边界的 API,并在unsafe操作中信任 trait 方法(如Read::read、Iterator::next、Hasher、ExactSizeIterator::len)返回的“长度/数量/索引/哈希”时,恶意实现方如何把这种信任变成堆越界写(OOB write)。读完本文,你将掌握该漏洞的完整 bug shape、三条判定 Gates、两类误报排除规则,以及把 trait 输出视为不可信输入的标准修补方案;同时会看到这一 bug class 在rust-review编排管线中的实际接入方式(manifest 声明、has_unsafe门控、worker 执行与发现文件格式)。
漏洞形态(Bug Shape):库信任 trait 返回值,unsafe越界写
adversarial-trait-finder的核心研究模型非常具体:
Bug shape(研究):库接受
T: Read,基于T::read()报告的字节数分配缓冲区,并通过未检查的unsafe写操作写入。敌对的impl Read for HostileType返回一个大于实际缓冲区的尺寸 → 越界写(OOB write)。
这与经典 Rust 安全审计中的“调用者即敌人”视角一脉相承:一旦一个 generic API 暴露给外部,T的具体实现就不受库作者控制。凡是把 trait 方法输出当作权威事实、再喂给unsafe长度信任汇点(length-trusting sink)的代码,都可能被一个合法但恶意的impl攻破。
在rust-review的编排体系中,这一 bug class 位于logic-correctness集群,编号为adversarial-trait,前缀TRAITADV。见 prompts/clusters/manifest.json 中logic-correctness集群的 passes 列表:
{ "bug_class": "adversarial-trait", "prefix": "TRAITADV", "prompt": "prompts/general/adversarial-trait-finder.md", "requires": ["has_unsafe"] }requires: ["has_unsafe"]意味着该 pass 仅在目标代码库包含unsafe(由 Phase 1 的能力探测决定)时才会被计划选中——因为这里的可利用后果正是unsafe代码中的内存破坏,纯 safe-Rust crate 不存在该 sink。plugins/rust-review/README.md 中也将“hostile generic trait impls”列为logic-correctness集群覆盖的逻辑正确性问题之一,并明确“The hostile-trait (TRAITADV) and closure-panic (CLOSUREPANIC) passes requirehas_unsafe”。
Gates:三条判定标准缺一不可
adversarial-trait-finder定义了三个必须同时满足的门槛(Gates),用于把真实的 TRAITADV 从“泛型库常见写法”中筛出来。
Gate 1:公开的泛型 API + trait 边界参数
代码必须是一个公开的(public)泛型 API,其参数带 trait 边界,例如T: Read、T: Iterator、T: Hasher、T: ExactSizeIterator,或自定义 trait。
对应到集群探测层面,prompts/clusters/logic-correctness.md 的 Phase A 提供了如下的rg种子,供 worker 先建立库存再逐项审查:
rg seed: "<\s*\w+\s*:\s*[A-Z]" # generic trait boundsrust-reviewworker 在执行这些种子搜索时要求使用rg(ripgrep 语法\s/\d/\b),若rg不可用则必须用 POSIX 类回退(\s→[[:space:]]、\d→[[:digit:]]、去掉\b),详见 agents/rust-review-worker.md 的搜索纪律。
Gate 2:trait 方法返回值流入 unsafe 或长度信任汇点
实现必须把 trait 方法的返回值(尺寸、数量、索引、哈希)喂进以下任一unsafe操作或长度信任汇点:
Vec::set_len—— 直接声明缓冲区长度为“敌报值”;get_unchecked/get_unchecked_mut—— 用敌报索引越界访问;ptr::write/copy_nonoverlapping在计算偏移处写入 —— 经典 OOB 写路径;from_raw_parts—— 用敌报长度构造切片/裸指针。
关键澄清(文档明确标注的陷阱):
Vec::with_capacity/reserve不是OOB 写汇点——它只预留容量,len仍为0,敌对的尺寸无法借此越界写。但攻击者控制的容量是独立的分配/内存耗尽 DoS,应作为单独问题记录,而不是当作内存破坏上报。
Gate 3:缺乏防御性校验
没有防御性检查确保报告值与实际一致。文档特别强调:
ExactSizeIterator::len()是提示(hint),不是保证(guarantee)——unsafe代码绝不能信任它。
同理,Read::read返回的“读取字节数”在Read契约中也不是权威保证(read本就可以返回比请求更少的字节,而一个恶意 impl 甚至可以谎报)。只要上游没有对 trait 输出做边界校验,Gate 3 即成立。
FPs:两种明确不算数的情况
检测器同时给出了两条“非漏洞”排除规则(False Positives),供 worker 在核查候选时直接放行:
- Trait 是密封的(sealed):
pub trait T: sealed::Sealed。由于实现被限定在库内部,外部无法提供恶意 impl,信任假设成立。 - 返回值仅作启发式且下游会校验:报告值只用于启发式判断(如粗略估算),并且在真正进入
unsafe汇点之前会被验证。此时信任链被下游校验切断,不构成漏洞。
这两条 FP 规则与rust-reviewworker 的核查纪律一致:先查现有校验与缓解(“Check for existing validation or mitigations before reporting”),再决定是否上报。
Patch:把 trait 方法输出当作不可信输入
文档给出的修补原则十分简洁:
Patch:将 trait 方法输出视为不可信(untrusted);对它们做边界约束(bound them);绝不直接喂给
set_len或get_unchecked。
具体落地通常包含三件事:
- 在进入
unsafe前校验:用真实可观测信息(如已读取字节数、切片真实长度、len <= cap断言)交叉核对 trait 返回值; - 改用安全 API:把
get_unchecked换成slice::get(..n).ok_or(...)?、把ptr::copy_nonoverlapping换成copy_from_slice,让越界变成显式Err而非 UB; - 在
// SAFETY:注释中指名上游校验者:文档化“谁保证了这个不变量成立”,而不是写一句无法验证的“caller ensures len <= 64”。
这与 agents/rust-review-worker.md 中 Finding File Format 的Recommendation字段模板完全同构——worker 上报时需给出可替换的安全代码写法并命名真实的校验来源。
在 rust-review 管线中的落地方式
触发条件与计划过滤
TRAITADV pass 是否进入某次审计,由 scripts/build_run_plan.py 的pass_filtered_out()决定。该函数遍历 pass 的requires列表,任何一个 capability flag 为假则硬性剔除该 pass:
for req in requires: if req not in KNOWN_REQUIRES: fail(...) if not flags[req]: return True也就是说,has_unsafe=false时 TRAITADV 会在计划阶段被直接丢弃,根本不会出现在 worker 的 spawn prompt 中(因此 worker 侧不存在“跳过该 pass”的选择——见 worker 协议中Skip subclasses: (none)的说明)。
执行顺序与冲突消解
在 prompts/clusters/logic-correctness.md 中,TRAITADV 是 Phase B 的第 2 个 pass。该集群用 Phase A 的一次性种子搜索建立共享库存(generic trait bounds、HashMap/HashSet、RefCell等),随后各 pass 复用同一库存,避免重复扫描。集群还给出了相邻 bug class 的去冲突规则,确保同一个根因不被重复贴上多个标签:
ORDEQHASHvsKEYMUT:手写Ord/Hash实现本身破坏契约是ORDEQHASH;对一个本已正确的 key 在集合内原地修改才是KEYMUT。CLOSUREPANIC(本集群)vsPANICUNWIND(memory-safety 集群):用户闭包在两个指针操作之间 panic 使unsafe脚手架不一致 →CLOSUREPANIC;容器元数据在 unwind 后残留陈旧 →PANICUNWIND。
TRAITADV 与ORDEQHASH同属“trait 实现危险”,但视角不同:前者是恶意实现者主动利用(外部impl谎报长度攻击库),后者是库自身实现违反契约(a == b ⟹ hash(a) == hash(b)等不变量被破坏导致 HashMap/BTreeMap 崩溃),见 prompts/general/ord-eq-hash-finder.md。
发现文件与后续判定
worker 确认的每个 TRAITADV 发现会以TRAITADV-NNN.md写入$(pwd)/.rust-review-results/<iso-timestamp>/findings/,frontmatter 包含id、bug_class: adversarial-trait、location(单条path:line)、function、confidence、worker,正文按七段结构撰写(Description / Code / Data flow / Reachability trace / Impact / Mitigations checked / Recommendation)。随后 dedup-judge 按(path, line, bug_class)等 Tier 合并重复项,fp-judge 给每个 primary 打fp_verdict与severity;severity_filter只影响最终REPORT.md的渲染,不决定 worker 是否上报。完整协议见 agents/rust-review-worker.md 与 skills/rust-review/SKILL.md。
实战核查清单(可直接复制使用)
对照 prompts/general/adversarial-trait-finder.md 原文,可把审计流程固化为以下清单:
- 找边界:
rg "<\s*\w+\s*:\s*[A-Z]"列出所有公开泛型 API 与 trait 边界。 - 找汇点:对每个边界候选,搜索
set_len、get_unchecked、ptr::write、copy_nonoverlapping、from_raw_parts的调用,判断其索引/长度来源是否为 trait 方法返回值。 - 找校验:确认汇点上游没有把报告值与真实长度交叉核对;确认 trait 未密封、返回值不是“仅启发式+下游校验”。
- 区分 DoS:若攻击面只落在
with_capacity/reserve,按“分配/内存耗尽 DoS”单独记录,不要混入内存破坏类。 - 写修复建议:给出带边界约束或安全 API 的替换代码,并在
// SAFETY:中指名真正的校验方。
按此清单,审计者可以稳定复现 TRAITADV 的完整判定路径:从 generic trait bound 到 unsafe 长度信任汇点,再到恶意 impl 的越界写后果。
小结
adversarial-trait-finder(TRAITADV)把“公开泛型 API + unsafe 长度信任”这一组合精确建模为可利用漏洞:T::read()/ExactSizeIterator::len()等 trait 输出只是提示而非保证,恶意实现可以谎报尺寸,使库在set_len、get_unchecked、copy_nonoverlapping上越界写。三条 Gates(泛型公开 API、unsafe 汇点、缺校验)与两条 FP 规则(密封 trait、下游校验)让检测器既能命中真漏洞又不至于把普通泛型库误报成高危;其requires: has_unsafe门控、硬过滤式计划选择、七段式 finding 文件与后续 dedup/fp 判定,展示了这类“基于研究 bug shape”的检测器在rust-review并行审计管线中从探测到报告的完整落地方式。
- AI 技能
- AI 插件
- 应用安全
- 网络安全
- AI 评测
【免费下载链接】skills
Trail of Bits Claude Code skills for security research, vulnerability detection, and audit workflows
相关推荐
Rufus U盘启动盘制作工具:5 分钟做出 Windows 11 安装盘
Rufus U盘启动盘制作工具:5 分钟做出 Windows 11 安装盘 系统崩了要重装,手里的 U 盘却只是普通存储盘,根本开不了机。Rufus 是一款免费
桌面应用开发工具Rust By Example 深度解析:使用 `dyn` 返回 Trait 对象(动态分发入门)
Rust By Example 深度解析:使用 dyn 返回 Trait 对象(动态分发入门) Rust 编译器在编译期必须知道每个函数的返回类型占用多少内存,
文档教程LobeHub deep-review 对抗式验证子代理:逐条证伪代码审查发现的设计与实现
LobeHub deep review 对抗式验证子代理:逐条证伪代码审查发现的设计与实现 本文以 LobeHub 仓库中 deep review 技能的核心模
人工智能AI 应用大模型AI Agent多智能体工具调用前端后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考