Install
openclaw skills install @modusensus/euthyna代码安全审计的判定纪律与交付门禁。当用户要求对一段代码、一个 PR、一次变更或一条已有的漏洞结论做安全审查与验证时使用。它做三件事:补上模型算不准的确定性事实(调用方、测试覆盖、git 历史来源),用 6 道门禁判定每条结论真假,拿不出证据的一律降级为「观察」而不是「发现」。不适用于:仅询问某个 CVE 的详情、仅要求跑一次现成扫描器、纯文档或格式化改动、以及用户只要一句快速摘要且明确接受风险时。
openclaw skills install @modusensus/euthynaεὔθυνα:雅典官员离任时必须交出账目接受审查,通不过就无法体面离任。 本技能的核心机制即此:说"审完了"不算数,证据交齐、门禁通过,才算交付。
本技能不找 bug,它管住结论。 找 bug 由模型与现成工具做;本技能负责: 每条结论必须过门禁,过不了就只能降级为「观察」。
用:
不用(直接拒绝或转其他技能):
这三条是本技能与「让模型仔细点」的全部区别。任何阶段、任何路径都不许跳过。
调用方数量、测试覆盖率、依赖版本、行号、提交哈希——这些一律不许靠印象回答。 模型可以在命令不可用时说「不可测量」,但不许估算后当成事实写进结论。
这条来自一次实测翻车:某包在 GitHub 上显示 5+ 人维护,而 npm 的实际权限列表只有 1 人; 另一个每周下载 1.6 亿次的包在某个数据源里显示零下载。手感估数字必错。
file:line,禁止占位符path:L123,有版本时写 path:L123 (commit abc1234)probably / likely / 大概是 —— 去追真实代码,追不了就明说追不了TODO、...、// 攻击者在这里做某事每个判据只能落到三态:已评估-干净 / 已评估-标记 / 因某原因不可评估。
用户给了什么?
│
├─ 一条已有的疑似漏洞断言 ──────────► 阶段 C:结论面验证
│ (「这是真的吗」「可利用吗」) 读 references/verification-gates.md
│ ★ 结论依赖「测过没有」→ 跑 coverage
│
├─ 一次变更(PR / diff / commit)────► 阶段 B:变更面审计
│ (「这个 PR 安全吗」) 读 references/change-audit.md
│ ★ 第一条命令:euthyna audit --base <分叉点>
│ (history + deps 一次跑完,见下节)
│ ★ 要谈测试覆盖 → 再跑 coverage
│
├─ 一个仓库 / 依赖面 ────────────────► 阶段 A:依赖面审计
│ (「依赖有没有问题」) 读 references/dependency-audit.md
│
└─ 一个仓库的整体安全审计 ───────────► 阶段 B 为主,A 与 C 作为子步骤
★ = 在动手人工读代码之前先跑,不是读完之后的补充说明。 产出器给的确定性事实,决定了人工阅读该往哪里使劲。
可以做多个阶段,但阶段之间不许互相替代。 特别是:阶段 B 报出的疑似发现,必须逐个走阶段 C 验证,不许直接写进报告当结论。
调用方、覆盖率、依赖漏洞、密钥这些不重造(见文末分工表)。但有两件事没人做、 且模型自己算不准,所以本技能自带一个零依赖 CLI:
| 测量 | 回答的问题 | 什么时候必须跑 |
|---|---|---|
audit | 上面两个问题一次跑完(history 默认追溯最初引入者 + deps 枚举 lockfile 全部依赖),合并一份报告 | 每次审计的第一条命令(阶段 B 开场) |
history | 这次变更删掉的代码来自哪个提交?那个提交是不是安全修复? | 需要单独重跑 history 时(如换 --base) |
coverage | 某个符号在测试运行中到底有没有被调用过? | 报告里要说「测过 / 没测过」时(阶段 B / C) |
# 唯一必需的参数是 --base(改前版本 / PR 分叉点):
node <euthyna 仓库>/bin/euthyna.js audit --base <改前版本> --repo <被审计的仓库>
# history / coverage 按需单独跑:
node <euthyna 仓库>/bin/euthyna.js history --base <改前版本> --repo <被审计的仓库>
node <euthyna 仓库>/bin/euthyna.js coverage --coverage <覆盖率文件绝对路径> --symbol <符号名>
⚠️ node bin/euthyna.js 这种相对路径一定失败。 审计时当前目录是被审计的项目,
不是 euthyna 仓库,会报 Cannot find module。要用 euthyna 仓库的路径,
并把被审计仓库用 --repo 显式传进去(--base / --head 相对它解析)。
退出码——2 与 0 的区别就是这套东西存在的意义:
| 码 | 含义 | 怎么办 |
|---|---|---|
0 | 已测量,无安全相关发现 | 继续,但要读「未评估的判据」一节 |
10 | 已测量,存在 security 分类的事实 | 提高优先级,逐条走阶段 C,不要直接当结论 |
1 | 用法错误 | 修命令。这不是测量结果 |
2 | 完全无法测量 | 不得当作干净。换测量方式,或把判据标为「不可评估」 |
命令不可用时(没装、没有检出):把判据标为「不可评估」,不要手工估算顶上。
操作手册(命令、真实输出样例、失效情形):references/fact-producers.md。
本技能定义的是测量层与判定层之间的接口:docs/fact-contract-zh.md。
要点:
dsh-trust-check 学到的:它的契约明写「不要拿 score 或 band 做门禁」)approximate 的事实不得参与门禁unknown 不是「干净」——三态里最常被误用的就是它事实的读法(能推出什么、不能推出什么):references/fact-contract.md。
无论走哪条路径,产出必须落到这个形状:
BUG #N TRUE POSITIVE — [一句话描述]
门禁全部通过。证据:path:L123 (commit abc1234)
复现:<可重跑的命令或 PoC 位置>
可利用性:EASY / MEDIUM / HARD
影响:具体到资金量 / 被提升的权限 / 被暴露的数据
BUG #N FALSE POSITIVE — [拒绝理由]
门禁 N(门禁名)FAIL:<具体证据>
例:第 98 行校验保证 packet_size >= 16,故 (packet_size - header_size) >= 8。
下溢在数学上不可能。
BUG #N INCONCLUSIVE — [无法判定的原因]
门禁 N(门禁名)未评估:<为什么>
第三态 inconclusive 必须存在。
Trail of Bits 的原始 fp-check 只有两态,因为它靠 Stop hook 无限强制继续直到补完;
DSH 上做不到(Stop hook 必须自带限流,见 docs/dsh-stop-gate-zh.md)。
所以必须有这个诚实出口——不许把「没查完」写成 FALSE POSITIVE。
上面的格式不是摆设:euthyna gate <报告文件> 会机械地逐条核对——
path:L123、必须有复现命令、必须说明影响、六门禁必须全过;缺证据、缺复现、或门禁与裁定互相矛盾(如 TRUE POSITIVE 却带 FAIL 门禁)的 finding,
会被**降级为「观察」**并以退出码 10 报出——不需要裁定者自觉,校验器替你卡住。
node <euthyna 仓库>/bin/euthyna.js gate <报告文件>
# 重跑每条复现命令核验(白名单工具、按 argv 执行不走 shell):
node <euthyna 仓库>/bin/euthyna.js gate <报告文件> --verify --cwd <被审计仓库>
0 = 全部通过;10 = 有 finding 被降级;2 = 报告无法读取 / 没有可校验的 finding。--verify 下复现命令跑不通同样构成降级——「说能复现」不算数,跑通才算。报告交出去之前,先过一遍 euthyna gate。 它校验的是报告自己的自我声明,
不测量目标仓库——因此它不能代替裁定,只能保证「拿不出证据的结论不会以已确证的面貌出去」。
<PROJECT>_EUTHYNA_AUDIT_<YYYY-MM-DD>.mdaudit(或 diff 有删除行时跑过 history);删自安全修复提交的代码已按最高风险处理coverage 输出支撑,或已标为「不可评估」2 的判据没有出现在「干净」一栏file:lineeuthyna gate 校验(退出码 0;有降级要读降级原因)按需加载。不要一次全读——渐进披露是这套东西能在长会话里保持有效的原因。
| 文件 | 内容 | 什么时候读 |
|---|---|---|
references/verification-gates.md | 阶段 C:路由、6 门禁、误报清单、恶魔代言人、PoC 规则 | 判定一条已有断言时(最常用) |
references/change-audit.md | 阶段 B:基线、深度 vs 风险、来源归属、爆炸半径、对抗建模 | 审一次变更时 |
references/dependency-audit.md | 阶段 A:清单/锁文件、三态、文体规范、禁止事项 | 审依赖面时 |
references/bug-classes.md | 9 类缺陷的专项检查与默认假设方向 | 定了缺陷类别之后 |
references/meta-mechanisms.md | 六个元机制:让流程不退化成走过场 | 审计开始时读一次 |
references/fact-producers.md | 操作手册:两个测量何时跑、命令怎么写、退出码怎么处理、真实输出样例、失效情形 | 跑产出器之前(阶段 B / C) |
references/fact-contract.md | 拿到事实之后能推出什么、以及它不能推出什么 | 读完产出器输出之后 |
技能文本自包含:以上文件都在
references/内,不依赖技能目录之外的路径, 可以整目录复制到任何技能根使用。⚠️ 但产出器本身是独立程序,不在技能目录里。复制技能不会把 CLI 一起带走。 新环境里要单独安装、或提供本项目的一份检出,否则相关判据只能标为「不可评估」—— 那也是一个诚实的结果,比手工估算强。见
references/fact-producers.md第一节。
| 已经有人做的事 | euthyna 怎么做 |
|---|---|
调用图 / 爆炸半径(dsh-tool-lens、dsh-blast-radius) | 不重造,消费其输出 |
覆盖率(dsh-code-coverage) | 不重造,消费其输出 |
依赖漏洞(dsh-dep-vuln-scan 等) | 不重造,消费其输出 |
密钥扫描(dsh-code-security) | 不重造,消费其输出 |
交付门禁机制(dsh-doublecheck、formalswarm) | 机制可借鉴;euthyna 的门禁内容是安全专属的 6 门禁 |
证据生命周期与 PoC 实验室(dsh-omv) | 可并存:dsh-omv 可作为事实契约的消费方 |
euthyna 只补两件没人做的确定性测量(见 docs/positioning-zh.md §7.2):
git 安全回归的机械判定,以及「符号 × 真实执行覆盖」的 join。