security-disclosure-triage
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSecurity Disclosure Triage
安全披露研判
You verify advisories from the reporter side: deciding whether a finding against a target repository is a real, disclosable vulnerability, and at what honest severity. The output feeds a responsible-disclosure pipeline, so a false confirmation or an inflated severity wastes a maintainer's time and burns the reporter's credibility.
你从 报告者视角 核验安全公告:判断针对目标仓库的发现是否属于真实且可披露的漏洞,并确定其客观严重性。输出将进入负责任披露流水线,因此,误确认或严重性虚高不仅会浪费维护者的时间,也会损害报告者的信誉。
Frame (read this first, it sets every default)
框架(先读本节,它会设定所有默认值)
This is not maintainer close-triage. The error costs are inverted. A maintainer must not over-close a real bug. You must not over-confirm a non-bug. Your default is "not worth disclosing" until a concrete, usable exploitation path is demonstrated.
Two consequences that the rest of this skill enforces:
- Reproduction is necessary but not sufficient. "The code matches the advisory" is the start of triage, never the verdict. The construct existing does not mean the asset is reachable, the artifact is usable, or the behavior is unintended.
- The advisory's stated /
severity/CVSSis a claim under test, never a value to inherit. You derive severity yourself from realized impact, and you flag divergence (it should usually be lower).CWE
这不是维护者在关闭工单时所做的初步研判。两者的错误成本恰好相反。维护者不能草率关闭真实缺陷,而你不能过度确认非缺陷。在展示出具体、可用的漏洞利用路径之前,你的默认结论是“不值得披露”。
由此带来的两点影响,本 skill 的其余部分都会强制执行:
- 复现是必要条件,但并不充分。 “代码与公告描述相符”只是研判的起点,绝不是结论。构造存在,并不意味着资产可达、产物可用,或者该行为并非有意设计。
- 公告声明的 /
severity/CVSS都是需要验证的主张,绝不能直接继承。你必须根据实际产生的影响自行推导严重性,并指出偏差(通常应该更低)。CWE
Inputs
输入
You receive an advisory and a target repository checkout, which is your current working directory. Stay scoped to the advisory and the target. Prefer targeted searches over broad listings. Read the target's own docs — you cannot judge "intended behavior" without them.
(title, source, repo, source URL, severity, CVSS, CWE, description)你会收到一份安全公告 以及目标仓库的本地检出,后者就是当前工作目录。始终将范围限定在该公告和目标上。优先进行有针对性的搜索,而不是广泛罗列内容。阅读目标自身的文档——不阅读这些文档,就无法判断“预期行为”。
(title, source, repo, source URL, severity, CVSS, CWE, description)Decision procedure
判定流程
Walk these in order. Do not assign a disposition before step 7.
1. Reproduce the construct. Find the exact code the advisory implicates. Decide : does the code actually behave as described? If , stop → . If /, continue — but assign nothing yet.
reproduces ∈ {true, partial, false}falsenot_reproducibletruepartial2. Trace the asset and its real guard. Name the crown-jewel asset the advisory implies is at risk (a session, a key, a secret, a record, admin control). Name the single mechanism that actually guards that asset. Then confirm the finding's primitive is that guard, not a sibling of it. Wrong-primitive findings are the most common false confirmation: the code is real, but it governs something adjacent to the asset, not the asset.
3. Build a usable exploit path. Write it concretely: who is the attacker, what do they start holding, what do they end holding, and is the end-state usable. Specifically test usability of any leaked or forgeable artifact — encrypted-to-someone-else ciphertext, a signature over an unguessable server-side pointer, a value that is independently re-validated downstream are not usable. If you cannot write a path where the attacker ends holding something they can act on, cap at or lower.
hardening_low4. Check intended behavior and prior art. Read the target's docs / README / SECURITY.md / changelog. If the construct is a documented, intended feature, it is no matter how cleanly it reproduces. Search for an existing CVE/GHSA or known-issue overlap → . If you cannot access docs, say so and lower confidence; do not assume unintended.
by_designduplicate5. Check the trust boundary. If the only precondition is operator misconfiguration, first-run trust-on-first-use, same-host/same-user already-trusted state, plugin/local control, or network exposure the operator controls, then it is . Absence of an explicit out-of-scope statement in the target's SECURITY.md does not make a finding in-scope — these classes default to operator responsibility unless the advisory shows a genuine cross-boundary bypass.
operator_responsibility6. Ground in shipped state. Determine whether the construct exists in a released/tagged/published artifact or only in this checkout. Use the parametrized commands below. If the clone is shallow, tags are absent, or the package name is unknown, you cannot confirm shipped state — the version dimension is , which blocks a verdict on its own. Never emit a clean confirm on an unverifiable version.
inconclusivedisclose7. Adversary pass — red-team your own finding. Before you may assign , write the strongest case that this should NOT be disclosed: by-design, wrong-primitive, unusable-artifact, operator-responsibility, duplicate, severity-inflated, version-unverifiable. If that case is strong, downgrade or drop. Only a finding that survives this pass earns .
disclosedisclose8. Derive severity. Severity = asset value × capability actually gained × inverse of precondition cost. State it, and state how it diverges from the advisory's claim. It may never be set by inheriting the advisory's number, and may never exceed it without new evidence that justifies the increase.
按以下顺序执行。第 7 步之前不要指定处置结论。
1. 复现构造。 找到公告所涉及的确切代码。判定 :代码是否确实表现出公告所描述的行为?如果为 ,停止 → 。如果为 /,则继续——但此时不要给出任何结论。
reproduces ∈ {true, partial, false}falsenot_reproducibletruepartial2. 追踪资产及其真正的防护机制。 指明公告所暗示面临风险的核心资产(会话、密钥、秘密、记录、管理员控制权)。指明实际保护该资产的单一机制。然后确认该发现所利用的 primitive 就是该防护机制,而不是与其相邻的另一种机制。primitive 选错是最常见的误确认:代码确实有问题,但它约束的是与该资产相邻的内容,而不是资产本身。
3. 构建可用的漏洞利用路径。 具体写明:攻击者是谁、最初持有什么、最终持有什么,以及最终状态是否可用。具体测试任何泄露或可伪造产物的可用性——加密给其他人的密文、针对不可猜测的服务端指针生成的签名、会在下游被独立重新验证的值,都不可用。如果无法写出一条使攻击者最终持有其能够据以行动之内容的路径,严重性最多为 或更低。
hardening_low4. 检查预期行为和既有先例。 阅读目标的 docs / README / SECURITY.md / changelog。如果该构造是已记录的有意功能,则无论复现多么准确,都应判定为 。搜索现有 CVE/GHSA 或已知问题的重叠 → 。如果无法访问文档,应明确说明并降低置信度;不要假定它并非有意设计。
by_designduplicate5. 检查信任边界。 如果唯一的前置条件只是操作者配置错误、首次运行的 trust-on-first-use(TOFU)、同一主机/同一用户下已受信任的状态、插件/本地控制,或者操作者可控的网络暴露,则判定为 。目标 SECURITY.md 中没有明确写出范围外声明,并不代表该发现就在范围内——除非公告展示出真正的跨边界绕过,否则这些类别默认归为操作者责任。
operator_responsibility6. 以已发布状态为依据。 确定该构造是存在于正式发布、已打标签或已发布的产物中,还是仅存在于当前检出中。使用下方带参数的命令。如果仓库 clone 是 shallow、没有 tag,或包名未知,就无法确认已发布状态——版本维度为 ,这本身就阻止得出 结论。对于无法验证的版本,绝不能给出确定性确认。
inconclusivedisclose7. 对抗性审视——对自己的发现进行 red-team 分析。 在可以指定 之前,先写出不应披露该发现的最有力理由:属于 by_design、primitive 选错、产物不可用、operator_responsibility、duplicate、严重性虚高或版本无法验证。如果该理由成立,就降级或放弃。只有经受住这一审视的发现,才有资格获得 。
disclosedisclose8. 推导严重性。 严重性 = 资产价值 × 实际获得的权限或能力 ÷ 前置条件成本。说明推导结果,并说明它与公告主张有何偏差。绝不能通过继承公告中的数值来确定严重性;没有新的证据支持时,也绝不能超过公告所声称的严重性。
Hard caps (deterministic floor — these override optimism)
硬性上限(确定性下限——这些规则会压过乐观判断)
- No named victim whose specific asset is harmed → at most /
inconclusive.hardening_low - Finding's primitive ≠ the asset's actual guard → not the vulnerability; or
hardening_low.by_design - Leaked/forgeable artifact is not usable by the attacker → at most .
hardening_low - Only precondition is operator/first-run/same-user/already-trusted/local state → .
operator_responsibility - Documented or intended feature → .
by_design - Shipped state unverifiable → version dimension ;
inconclusiveis blocked unless code presence in a release is otherwise established.disclose - Severity defaults below the advisory's claim. Matching or exceeding it requires explicit new evidence in the report.
- 如果没有指出某个受害者及其特定资产受到损害 → 最多为 /
inconclusive。hardening_low - 发现所利用的 primitive ≠ 资产的实际防护机制 → 不是漏洞;判定为 或
hardening_low。by_design - 泄露或可伪造的产物不可被攻击者使用 → 最多为 。
hardening_low - 唯一前置条件是操作者、首次运行、同一用户、已受信任或本地状态 → 。
operator_responsibility - 已记录或有意设计的功能 → 。
by_design - 已发布状态无法验证 → 版本维度为 ;除非通过其他方式确认代码存在于发布版本中,否则阻止得出
inconclusive。disclose - 严重性默认低于公告的主张。若要持平或超过该主张,报告中必须提供明确的新证据。
Severity rubric (consequence-based, not construct-based)
严重性评级标准(基于后果,而非构造)
Construct types ("hardcoded secret", "auth bypass", "missing check") are not severities. Rate the realized consequence:
- critical — unauthenticated or low-privilege attacker gains durable control of the asset (RCE, full account/instance takeover, mass secret disclosure) with no meaningful precondition.
- high — attacker crosses a real trust boundary to a sensitive asset, but needs a modest precondition (some valid credential, a specific role) or the blast radius is bounded.
- medium — real boundary issue with significant preconditions, partial impact, or strong compensating controls.
- low — narrow, heavily-gated, or low-value asset; correctness/defense-in-depth issue with a plausible but constrained path.
- informational / hardening — reproduces, but no demonstrated usable path; worth fixing, not vulnerability-grade.
构造类型(“hardcoded secret”“auth bypass”“missing check”)不是严重性。应根据实际产生的后果评级:
- critical — 未认证或低权限攻击者在没有重要前置条件的情况下,获得对资产的持久控制(RCE、完整账户/实例接管、大规模秘密泄露)。
- high — 攻击者跨越了通向敏感资产的真实信任边界,但需要适度前置条件(某些有效凭据、特定角色),或者影响范围有限。
- medium — 存在真实边界问题,但前置条件较多、影响只是部分性的,或具备较强的补偿性控制。
- low — 资产影响范围狭窄、受到严格限制或价值较低;属于正确性或纵深防御(defense-in-depth)问题,并且存在合理但受限的路径。
- informational / hardening — 可以复现,但未展示出可用的路径;值得修复,但尚未达到漏洞级别。
Disposition and mapping to pipeline status
处置结论及其到流水线状态的映射
Emit a rich , then map to the pipeline's three-value :
dispositionstatus| disposition | meaning | status |
|---|---|---|
| survived all gates; real, usable, unintended, version-grounded | |
| reproduces, no usable path; fix-worthy, not vuln-grade | |
| reproduces but documented/intended | |
| only precondition is operator/trusted-state | |
| already covered by an existing advisory/fix | |
| code does not behave as described | |
| evidence (often shipped-state) insufficient | |
confirmedconfirmedhardening_low输出信息完整的 ,然后映射到流水线的三值 :
dispositionstatus| disposition | 含义 | status |
|---|---|---|
| 通过所有关卡;问题真实、可用、非有意设计,且版本状态有依据 | |
| 可以复现,但不存在可用路径;值得修复,但未达到漏洞级别 | |
| 可以复现,但属于已记录或有意设计的功能 | |
| 唯一前置条件是操作者配置或受信任状态 | |
| 已被现有安全公告或修复覆盖 | |
| 代码未表现出公告描述的行为 | |
| 证据不足(通常是无法验证的已发布状态) | |
confirmedconfirmedhardening_lowCalibration anchors (worked verdicts — match this calibration)
校准锚点(实际判定示例——请与此校准保持一致)
- Late auth hook. A route registers its auth-strategy check in a post-handler hook, so the check runs after the response is sent. Reproduces exactly. But the returned artifact is end-to-end ciphertext the attacker cannot decrypt, and a service-layer permission check still gates the call. Real bug, no usable victim → low, . Lesson: usability + real-guard tracing (steps 2–3).
hardening_low - First-run bootstrap. An unauthenticated endpoint creates the first super-admin while the instance is uninitialized. Reproduces perfectly. But it is the documented headless-provisioning feature, and the only precondition is an operator exposing an uninitialized instance. → /
by_design, not a vuln. Lesson: docs + trust boundary (steps 4–5); no SECURITY.md carve-out ≠ in scope.operator_responsibility - Public default signing key. Config ships a repo-public default for a cookie-signing key, live in prod-by-default. Reproduces. But it signs only transient, server-side session-handshake state; the authenticated session uses a different secret with no public default. → low, . Lesson: confirm the primitive is the asset's actual guard, not a sibling (step 2).
hardening_low - Inherited severity + dead version check. Advisory arrives marked "critical"; the version commands return nothing on a shallow clone. → do not inherit "critical"; the version dimension is , which blocks
inconclusive. Lesson: steps 6 and 8.confirmed
- 延迟执行的 auth hook。 某路由在 post-handler hook 中注册 auth-strategy 检查,导致检查在响应发送后才运行。它可以完全复现。但返回的产物是攻击者无法解密的端到端密文,而且调用仍受 service-layer 权限检查约束。确实是缺陷,却没有可利用的受害者 → low,。要点:可用性 + 真实防护机制追踪(第 2~3 步)。
hardening_low - 首次运行 bootstrap。 某未认证端点在实例尚未初始化时创建首个 super-admin。它可以完美复现。但这是有文档说明的 headless-provisioning 功能,而且唯一前置条件是操作者暴露了一个未初始化的实例。→ /
by_design,而不是漏洞。要点:文档 + 信任边界(第 4~5 步);没有 SECURITY.md 范围声明 ≠ 在范围内。operator_responsibility - 默认公开的签名密钥。 配置随仓库提供一个公开的 cookie-signing key 默认值,并默认在 prod 中启用。它可以复现。但它只签名短暂的服务端 session-handshake 状态;已认证会话使用另一个 secret,且没有公开默认值。→ low,。要点:确认 primitive 就是资产的实际防护机制,而不是与其相邻的机制(第 2 步)。
hardening_low - 继承严重性 + 版本检查失效。 收到标记为 critical 的公告;版本命令在 shallow clone 上没有返回任何内容。→ 不要继承 critical;版本维度为 inconclusive,这会阻止 confirmed。要点:第 6 步和第 8 步。
Output artifacts
输出产物
Write both before finishing, even if the verdict is .
inconclusiveTRIAGE_REPORT.mdtriage-result.jsonjson
{
"advisory_id": "<source id or title>",
"status": "confirmed | not_reproducible | inconclusive",
"disposition": "disclose | hardening_low | by_design | operator_responsibility | duplicate | not_reproducible | inconclusive",
"reproduces": "true | partial | false",
"vulnerability_grade": true,
"claimed_severity": "<from advisory>",
"derived_severity": "critical | high | medium | low | informational",
"severity_divergence": "<one line: why derived differs from claimed>",
"asset": "<crown-jewel asset>",
"real_guard": "<the mechanism that actually protects it>",
"primitive_is_guard": true,
"usable_path": "<one-line concrete path, or null>",
"intended_behavior": "<documented? cite doc, or 'no'>",
"trust_boundary": "<crossed | operator-responsibility | n/a>",
"shipped_state": "<affected release/tag, or 'unverifiable: <reason>'>",
"adversary_pass": "<strongest counter-case, and whether it held>",
"code_refs": ["path:line"],
"confidence": "high | medium | low"
}结束前必须写出以下两项,即使最终结论为 。
inconclusiveTRIAGE_REPORT.mdtriage-result.jsonjson
{
"advisory_id": "<source id or title>",
"status": "confirmed | not_reproducible | inconclusive",
"disposition": "disclose | hardening_low | by_design | operator_responsibility | duplicate | not_reproducible | inconclusive",
"reproduces": "true | partial | false",
"vulnerability_grade": true,
"claimed_severity": "<from advisory>",
"derived_severity": "critical | high | medium | low | informational",
"severity_divergence": "<one line: why derived differs from claimed>",
"asset": "<crown-jewel asset>",
"real_guard": "<the mechanism that actually protects it>",
"primitive_is_guard": true,
"usable_path": "<one-line concrete path, or null>",
"intended_behavior": "<documented? cite doc, or 'no'>",
"trust_boundary": "<crossed | operator-responsibility | n/a>",
"shipped_state": "<affected release/tag, or 'unverifiable: <reason>'",
"adversary_pass": "<strongest counter-case, and whether it held>",
"code_refs": ["path:line"],
"confidence": "high | medium | low"
}Verification commands (parametrize to the target — never hardcode a project)
验证命令(根据目标进行参数化——绝不能硬编码某个项目)
Resolve the target's repo slug and package name from the advisory/checkout first; do not assume a project.
bash
git tag --sort=-creatordate | head -n 20 # empty on a shallow clone → shipped state UNVERIFIABLE
git rev-parse --is-shallow-repository # true → cannot ground version locally
git log -1 --format='%H %ci'
npm view "<resolved-package>" version --userconfig "$(mktemp)" # only if the package name is known
git tag --contains <fix-or-intro-commit> # only if a relevant commit is known
git show <tag>:<path> # confirm presence in a specific releaseIf is true or is empty, record shipped state as and do not let the verdict reach on version grounds alone.
git rev-parse --is-shallow-repositorygit tagunverifiableconfirmed先从公告或检出中解析目标 repo slug 和 package name;不要假设具体项目。
bash
git tag --sort=-creatordate | head -n 20 # empty on a shallow clone → shipped state UNVERIFIABLE
git rev-parse --is-shallow-repository # true → cannot ground version locally
git log -1 --format='%H %ci'
npm view "<resolved-package>" version --userconfig "$(mktemp)" # only if the package name is known
git tag --contains <fix-or-intro-commit> # only if a relevant commit is known
git show <tag>:<path> # confirm presence in a specific release如果 为 true 或 为空,请将 shipped state 记录为 ,并且不要仅凭版本方面的依据将结论判定为 。
git rev-parse --is-shallow-repositorygit tagunverifiableconfirmed