Skip to content
Back to skills

Euthyna

ASecurity

代码安全审计的判定纪律与交付门禁。当用户要求对一段代码、一个 PR、一次变更或一条已有的漏洞结论做安全审查与验证时使用。它做三件事:补上模型算不准的确定性事实(调用方、测试覆盖、git 历史来源),用 6 道门禁判定每条结论真假,拿不出证据的一律降级为「观察」而不是「发现」。不适用于:仅询问某个 CVE 的详情、仅要求跑一次现成扫描器、纯文档或格式化改动、以及用户只要一句快速摘要且明确接受风险时。

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 21, 2026
securityrustshellnodedockergitsecurity

Works with

  • cursor
  • cli

Security analysis

A100/100

Pro scans all 8 files and shows the line behind each finding

Scanned October 21, 2026

npx -y skills add slow-stack/euthyna --skill euthyna --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Euthyna?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Euthyna
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/slow-stack-euthyna/badge)](https://www.skillsdirectory.com/skills/slow-stack-euthyna)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: euthyna
description: 代码安全审计的判定纪律与交付门禁。当用户要求对一段代码、一个 PR、一次变更或一条已有的漏洞结论做安全审查与验证时使用。它做三件事:补上模型算不准的确定性事实(调用方、测试覆盖、git 历史来源),用 6 道门禁判定每条结论真假,拿不出证据的一律降级为「观察」而不是「发现」。不适用于:仅询问某个 CVE 的详情、仅要求跑一次现成扫描器、纯文档或格式化改动、以及用户只要一句快速摘要且明确接受风险时。
whenToUse: 用户要求审计代码或仓库的安全面、验证一条疑似漏洞结论真假、判定某个发现是否可利用、审查一次变更是否引入安全回归,或要求「审完再交付」时使用。只查密钥、只查依赖版本这类单一主题,直接用对应专项技能,不要触发本技能。
disable-model-invocation: true
user-invocable: true
license: Apache-2.0
---

# euthyna — 代码安全审计的判定纪律

> εὔθυνα:雅典官员离任时必须交出账目接受审查,通不过就无法体面离任。
> 本技能的核心机制即此:**说"审完了"不算数,证据交齐、门禁通过,才算交付。**

**本技能不找 bug,它管住结论。** 找 bug 由模型与现成工具做;本技能负责:
每条结论必须过门禁,过不了就只能降级为「观察」。

---

## 何时用 / 何时不用

**用**:

- 用户要求审计代码、仓库、一次变更(PR / commit / diff)的安全面
- 用户拿来一条疑似漏洞,问「这是真的吗」「是否可利用」
- 用户要求审查某次变更是否把已有的安全防护改弱了
- 用户要求「验证完再交付」

**不用**(直接拒绝或转其他技能):

- 只问某个 CVE / 某个依赖的详情 → 用依赖审计类工具
- 只要求跑一次现成扫描器并贴出结果 → 那是工具调用,不是审计
- 纯文档、格式化、lint 类改动 → 无安全面
- 用户明确只要快速摘要并接受风险 → 说明这是「非审计模式」,不套用本技能的裁定格式

---

## 三条不可跳过的规则

这三条是本技能与「让模型仔细点」的全部区别。任何阶段、任何路径都不许跳过。

### 规则 1:可测量的量一律由命令产出,模型只做判读

调用方数量、测试覆盖率、依赖版本、行号、提交哈希——**这些一律不许靠印象回答**。
模型可以在命令不可用时说「不可测量」,但不许估算后当成事实写进结论。

> 这条来自一次实测翻车:某包在 GitHub 上显示 5+ 人维护,而 npm 的实际权限列表只有 1 人;
> 另一个每周下载 1.6 亿次的包在某个数据源里显示零下载。**手感估数字必错。**

### 规则 2:证据强制到 `file:line`,禁止占位符

- 每条主张引用具体位置,格式 `path:L123`,有版本时写 `path:L123 (commit abc1234)`
- 禁用 `probably` / `likely` / `大概是` —— 去追真实代码,追不了就明说追不了
- 演示代码(PoC)里禁止 `TODO`、`...`、`// 攻击者在这里做某事`
- **一旦发现 PoC 用了人为绕过**(mock、stub、禁用检查),该 PoC 判定**无效**

### 规则 3:缺数据 ≠ 干净

每个判据只能落到三态:**已评估-干净 / 已评估-标记 / 因某原因不可评估**。

- 一次什么都没测到的运行,产出的是「不可评估」,**不是**「没发现问题」
- 引用任何「干净」结论之前,先看覆盖表
- **数字必须逐字引用**,不得重新推导、四舍五入或修饰
- 没发现不等于背书

---

## 入口决策树

```
用户给了什么?
│
├─ 一条已有的疑似漏洞断言 ──────────► 阶段 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 验证**,不许直接写进报告当结论。

### 模式词(斜杠命令)

用户用斜杠命令进来时,按下表把模式映射到阶段与第一条命令。**词表只在这里维护**,
各宿主命令文件(Cursor / OpenCode / Copilot / Hermes)指向本节,不各自重抄一份。

| 你打 | 走哪条支路 | 第一条命令 |
|---|---|---|
| `/euthyna pr` | 阶段 B 变更面 | `euthyna audit`(省略 `--base` 即按分叉点推断并声明) |
| `/euthyna graph` | 阶段 B 的来源谱系视图 | `euthyna audit --graph`(同样可省略 `--base`) |
| `/euthyna repo` | 阶段 A 依赖面 | `euthyna deps --all` |
| `/euthyna claim <结论>` | 阶段 C 结论面 | `euthyna coverage --symbol <名>` |
| `/euthyna gate <报告>` | 校验一份已写的报告 | `euthyna gate <报告>` |
| `/euthyna help` | 只打印这张表 | 不跑命令,不改变状态 |

`/euthyna graph` 不是新测量:`--graph` 只是把 `history` 已经给出的归属画成 Mermaid。
**图上没有第二条边不等于内容没被移过**,边界见 references/fact-producers.md。

---

## 本技能自带的两个确定性测量

调用方、覆盖率、依赖漏洞、密钥这些**不重造**(见文末分工表)。但有两件事没人做、
且模型自己算不准,所以本技能自带一个零依赖 CLI:

| 测量 | 回答的问题 | 什么时候**必须**跑 |
|---|---|---|
| `audit` | 上面两个问题**一次跑完**(history 默认追溯最初引入者 + deps 枚举 lockfile 全部依赖),合并一份报告 | **每次审计的第一条命令**(阶段 B 开场) |
| `history` | 这次变更**删掉**的代码来自哪个提交?那个提交是不是安全修复? | 需要单独重跑 history 时(如换 `--base`) |
| `coverage` | 某个符号在测试运行中**到底有没有被调用过**? | 报告里要说「测过 / 没测过」时(阶段 B / C) |

```powershell
# --base 可以省略:省略时按 merge-base(HEAD, origin/main) 推断,并在报告里声明为 range-inferred
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`。

### 执行纪律(复现命令与 PoC)

`--verify` 与 PoC 会在**用户的机器**上执行命令。跑任何复现/验证命令前:

- **先取得用户明确批准**,把要跑的命令原文列出来——不跑没报备的命令
- 能在沙箱/临时容器里跑的(如 Docker),**优先沙箱**;无法沙箱时说明风险再跑
- 报告里的 PoC 是给「拿到报告的人」复现用的;裁定过程中 agent 自己执行的每条命令同样适用本节

---

## 事实契约(测量与判定之间的接口)

本技能定义的是**测量层与判定层之间的接口**:`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)

上面的格式不是摆设:`euthyna gate <报告文件>` 会机械地逐条核对——

- **TRUE POSITIVE**:证据必须到 `path:L123`、必须有复现命令、必须说明影响、六门禁必须全过;
- **FALSE POSITIVE**:至少一条门禁 FAIL 且带具体证据;
- **INCONCLUSIVE**:至少一条门禁未评估,且没有任何 FAIL。

缺证据、缺复现、或门禁与裁定互相矛盾(如 TRUE POSITIVE 却带 FAIL 门禁)的 finding,
会被**降级为「观察」**并以退出码 `10` 报出——不需要裁定者自觉,校验器替你卡住。

```powershell
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>.md`
- 写文件失败的降级顺序:当前工作目录 → 用户桌面 → 临时目录 → **最后手段**才输出到聊天并提示用户手动保存

---

## 交付前的自检(逐条打勾,缺一条不许说「审完了」)

- [ ] 每个疑似发现都走了**完整的**阶段 C,不是「看一眼觉得是假的」
- [ ] **跑过 `audit`(或 diff 有删除行时跑过 `history`)**;删自安全修复提交的代码已按最高风险处理
- [ ] 报告里每句「测过 / 没测过」都有 `coverage` 输出支撑,或已标为「不可评估」
- [ ] **退出码为 `2` 的判据没有出现在「干净」一栏**
- [ ] 每条结论都带 `file:line`
- [ ] 每条结论都标了三态之一(干净 / 标记 / 不可评估)
- [ ] 覆盖表写清了**哪些判据没评估、为什么**
- [ ] 恶魔代言人 13 问逐条答过(含防假阴性的第 12、13 问)
- [ ] 报告文件已落盘
- [ ] 报告已通过 `euthyna 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。

Files in this skill

  • SKILL.md15.5 KB
  • references/bug-classes.md5.1 KB
  • references/change-audit.md8.3 KB
  • references/dependency-audit.md5.3 KB
  • references/fact-contract.md5.1 KB
  • references/fact-producers.md20.8 KB
  • references/meta-mechanisms.md7.3 KB
  • references/verification-gates.md13.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.