关于 create-rule
create-rule 是面向 OpenTaint 规则编写者的安全技能。它检查已有的源或汇规则覆盖,为缺失项创建库规则,并通过测试样例验证。
主要功能
- 01查找已有规则覆盖
- 02创建带标签的源或汇规则
- 03编写测试连接并运行测试
- 04更新规则跟踪文件
适用场景
- 01为软件包补充源或汇覆盖
- 02在修复模式下调整已标记规则
- 03用样例检查规则行为
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ seqra/ opentaint --skill create-rule安装后在 Claude Code 中输入/create-rule确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/debugging.mdjava.mdscripts/check-test-result.py详细介绍
技能:创建规则
OpenTaint 是一种全程序、过程间、字段敏感的别名分析引擎。它已经能够沿着可见的应用代码、调用、别名和各个字段传播;自定义规则和近似规则只用于建模指定的源、汇或不透明方法边界。编译时常量和字面量不携带污点,因此输出仅为常量的源或载体不会引入污点。
一个单元会指定要检测的源或汇成员。如果现有内置规则或项目库规则已实现该边界,就识别并使用该规则;否则编写自定义规则,然后针对其测试项目验证该单元。每条选用或创建的源规则都必须带有该单元的 untrusted-data-source 标签;每条选用或创建的汇规则都必须带有其单元组的 *-sink 标签。生产环境中的关联使用这些标签,只有在需要新建汇标签时才会稍后组装。
输入
由调用方提供;省略时使用默认值。仅当缺少必填输入且没有合理默认值时才进行询问
project-root(可选)— 目标项目的根目录。Opentaint 会将所有分析产物保存在固定的<project-root>/.opentaint/目录下,因此下文中的每个.opentaint/...路径都会解析到该目录。默认值:当前目录language(必填)— 此项目的目标语言及语言专属说明side(必填)—sources或sinks;单元所属的一侧。它决定单元文件、示例风格和测试子项目unit(必填)— 用于标识单元的<package-kebab>。其规范和跟踪记录位于.opentaint/tracking/rules/<side>/<unit>.yaml;测试项目位于.opentaint/test-projects/<unit>/<side>,编译后的模型位于.opentaint/test-compiled/<unit>/<side>fix-target(可选)— 主扫描标记出的已创建规则<path>#<id>,以及需要修正的误报或漏报。设置后,应收窄或扩大该条规则,而不是从单元开始编写
工作流
1. 检查现有覆盖
浏览内置库规则和 .opentaint/rules,判断是否已有规则与单元中的每个条目匹配。如果有,不要编写重复规则:在 .opentaint/tracking/rules/<side>/<unit>.yaml 中将其 rule_id 设为 <relative-yaml-path>#<rule-id>。此字符串仅用于跟踪记录。不要向任何生产规则添加 rule 引用;生产环境中的关联仍基于标签,稍后再编写。以下命令会打印内置规则根目录。使用语言参考浏览这两个根目录,并按条目的精确语言专属标识符搜索:
opentaint health --rules
阅读 .opentaint/tracking/rules/tags.yaml。源单元必须带有 tag: untrusted-data-source;每个汇单元组的规则都必须扩展其现有或新注册的一个 *-sink 标签。
在修复模式下,不要从单元开始编写:直接转到那条被标记的规则,按照步骤 4 中有关误报或漏报的指导调整规则,重新运行本侧的测试,然后停止;单元的其他条目保持不变。否则,如果条目已带有 rule_id,就继续使用这些记录的实现,仅为仍未覆盖的条目编写规则。如果单元只完成了部分阶段(部分阶段为 done,其他阶段未完成),就基于磁盘上的现有产物从第一个未完成阶段继续,而不是重新开始。
2. 编写库规则
根据单元的准确成员标识符、记录的签名及相关声明元数据推导每条规则的模式。将污点值绑定到 $UNTRUSTED,并在库规则上添加单元/组标签。汇点标签属于整个语义组,而不是单个方法。一条规则可以涵盖组中的多个方法,也可以有多条规则携带相同标签。规则形式和位置请参阅语言参考。
对于 side: sinks,遍历 groups:确保 groups[].sinks 下的每个方法都有对应的实现 rule_id,并将外层的 groups[].tag 添加到你创建的每条自定义规则上。对于 side: sources,使用单元顶层的标签。
3. 编写测试连接规则
库规则本身不会产生任何结果——要测试它,需在临时测试连接规则中将它连接到通用污点标记。针对该侧,在测试项目的标记规则中编写一条连接规则,一端引用通用标记,另一端引用为该单元选定的每个库 rule_id,这样正向样例中的污点值就会从标记流向规则(汇点侧),或从规则流向标记(源点侧)。测试连接规则只存在于测试项目中,绝不能放在被扫描的规则树中。其形式、命名和位置请参阅语言参考。
4. 测试直至成功
直接以前台阻塞命令运行规则测试,并等待其退出——绝不要将测试放到后台运行或使用 Monitor。加载你的库规则、测试连接规则和标记规则,然后反复迭代,直至所有样例都通过:
opentaint test rule run .opentaint/test-compiled/<unit>/<side> \
-o .opentaint/test-results/<unit>/<side> \
--ruleset .opentaint/rules --ruleset .opentaint/test-projects/<unit>/<side>/test-rules \
--passthrough-approximations .opentaint/pass-through
test rule run 会自动加载内置规则,因此只需传入你的自定义规则集。按原样应用直通近似规则;即使为空也无妨。使用随附脚本读取结果——它会显示通过/失败计数并列出失败样例,因此你无需手动解析 JSON:
uv run <skill-dir>/scripts/check-test-result.py <unit>/<side>
根据报告的结果修复:
falseNegative→ 匹配范围过窄,应扩大范围,并确认元变量名称在各分支之间以及refs和on之间一致falsePositive→ 匹配范围过宽,应添加排除条件或净化器skipped/disabled→ 规则未被测试;修复样例的rule-test.yaml入口或rule-id,或者启用该规则
各类修复对应的具体模式运算符请参阅语言参考。
5. 正向样例无法收敛时升级处理
如果修复规则约 3 次后正向样例仍未通过,原因可能不是编辑规则就能解决的。按照 references/debugging.md 定位原因,然后将 stages.tests_passing: pending 保持为待处理状态,并根据 Output 报告问题,而不是盲目修改。
输出
交付物
.opentaint/rules下的自定义库规则文件.opentaint/tracking/rules/<side>/<unit>.yaml— 已更新该单元的条目(参见 Tracking)
摘要
- 实现库规则的 ID,并注明哪些是内置规则、哪些是新建规则;该侧的一行测试摘要;以及实际使用的完整
test rule run命令 - 如果在第 5 步受阻:将
stages.tests_passing保持为待处理状态,并说明原因 —- 失败样例的数据流中有库方法被丢弃 → 列出需要建模的方法,以便在重新分派前进行近似处理
- 没有被丢弃的方法,且没有明确的规则原因 → 未能收敛,需由编排器介入
跟踪
此技能会为每个单元条目记录其实现规则的 rule_id,以及该单元的 stages.tests_passing。rule_id 是 <relative-yaml-path>#<id> 定位符,指向为该条目创建的自定义库规则,或已证明能够覆盖该条目的现有内置库规则。保留源单元顶层的 tag 和每个接收器 groups[].tag,这些标签是作者契约。被阻塞的单元应保持 tests_passing: pending。
.opentaint/tracking/rules/sources/<package-kebab>.yaml — 每个软件包一个源单元(一个依赖项可以跨越多个软件包),文件以该软件包命名,并将 . 替换为 -。tag 始终为可复用的 untrusted-data-source 组。dependencies 指明软件包所属的依赖项;sources 中的每个条目都是一个入口点 { method, signature, note, rule_id }(method 和 signature 使用计划中精确的特定语言标识符);stages 跟踪该单元的规则编写进度;如果该单元无法通过测试,则在其下添加 blocker 字符串。请通过注释明确说明
dependencies:
- <dependency-id>
tag: untrusted-data-source
sources:
- { method: "<qualified-member>", signature: "<language-signature>", note: untrusted message payload, rule_id: null }
stages:
test_project: pending
tests_passing: pending
.opentaint/tracking/rules/sinks/<package-kebab>.yaml — 每个软件包一个接收器单元(一个依赖项可以跨越多个软件包,每个软件包各自有一个单元),文件以该软件包命名,并将 . 替换为 -。dependencies 指明软件包所属的依赖项。groups 按可复用的接收器标签划分该软件包的危险操作;每个组的格式为 { tag, sinks },每个接收器的格式为 { method, signature, note, rule_id }。标签属于组,绝不属于单个方法:一条规则可以覆盖多个方法,也可以有多条规则扩展同一漏洞类别。method 和 signature 使用计划中精确的特定语言标识符。stages 跟踪该单元的规则编写进度。请通过注释明确说明
dependencies:
- <dependency-id>
groups:
- tag: path-traversal-sink
sinks:
- { method: "<qualified-member>", signature: "<language-signature>", note: writes data to an untrusted path, rule_id: null }
stages:
test_project: pending
tests_passing: pending
约束
- 库规则必须包含
options.lib: true和severity: NOTE - 创建的源规则必须带有
untrusted-data-source标签;创建的接收器规则必须带有其所属接收器组已注册的*-sink标签 - 测试连接必须包含
metadata.cwe和metadata.short-description - 在测试连接中,
refs和on子句中的元变量名称必须一致,否则连接无法建立。在每条库源规则和接收器规则中,将受污值绑定到$UNTRUSTED - 测试连接的
rule路径相对于规则集根目录:标记规则在测试项目的规则目录下解析,库规则在内置或自定义的扫描规则树下解析 - 规则 ID 必须全局唯一
- 自定义库规则放在扫描规则树中;测试连接只能放在测试项目的标记规则中
- 绝不扫描主项目模型
- 绝不尝试编辑测试项目
注意事项
- 如果你认为测试项目有误,请将其退回上游
- 如果某个正向测试因库方法丢弃了污点而无法通过,这不是规则错误——应将其作为近似处理问题上报(参见第 5 步),不要为了强行通过而扩大规则范围
- 生成的规则文件中不要包含注释