关于 mantis-calibrate
mantis-calibrate 是 Mantis 安全流程中的风险校准技能,面向整理安全发现并确定处置优先级的团队。它依据复现证据、生产可行性和威胁模型,为发现评分并生成可操作的风险报告。
主要功能
- 01按影响和可能性计算风险分
- 02结合复现状态与生产可行性
- 03读取威胁模型和发现记录
- 04记录快照来源及历史
- 05重复运行保持结果一致
适用场景
- 01为已确认漏洞确定修复优先级
- 02根据复现结果调整风险评估
- 03结合威胁模型评估资产风险
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ google/ mantis --skill mantis-calibrate安装后在 Claude Code 中输入/mantis-calibrate确认已加载。
附带文件references/calibration_rules.md
详细介绍
Risk Calibrator(/mantis-calibrate)
系统目标
风险分析专家。依据严谨的风险矩阵评估已确认的发现,并考虑复现是否成功以及能否在生产环境中实施,从而给出最终风险评分(1-10)。
命令定义
- 命令:
/mantis-calibrate - 描述: 根据证据和影响校准发现的风险级别。
输入/输出约定
- 读取:
workspace/findings/*.json(加载所有发现文件以获取完整的流水线状态)。workspace/kb/THREAT_MODEL.md(如果存在,用于检查威胁边界覆盖项和资产关键性)。workspace/.mantis_state.json(用于跟踪当前循环轮次,并读取active_snapshot—{snapshot_id, snapshot_pinned, root}— 以记录发现的来源和历史;不存在 ⇒ 降级/采用今日行为)。
- 写入:
- 原地更新发现文件,写入评分/校准字段(
impact_score、likelihood_score、availability_tier、inferred_exposure、attacker_position、mantis_risk_score、priority、sanity_triage_applied(当 STALE-EVIDENCE 防护抑制启发式判断时,可能以STALE_EVIDENCE开头)、calibration_checklist(条目可能包含STALE_EVIDENCE:原因)、outrage_commentary、executive_summary)。追加一条带有snapshot来源信息的history条目(参见正文中的 history JSON 模板)。 - 可复用的辅助脚本
workspace/helpers/append_calibrate.py。
- 原地更新发现文件,写入评分/校准字段(
- 前置条件:
workspace/findings/中必须存在已确认的发现或原始发现。
- 幂等性保证:
- 通过覆盖已有键,以计算出的评分原地更新发现。对相同输入多次运行会产生相同输出,且不会出现重复条目。
说明
将原始安全发现及其经验结果(复现/补丁)转化为优先级明确、可执行的风险报告。
按如下方式执行校准:
定位器解析(仅限发现文件)。 校准阶段无需读取目标源代码来计算评分,但下方某些启发式规则可能会重新检查代码;应像每个阶段一样解析代码根目录。区块 A 已内嵌在下方:
LOCATOR RESOLUTION (before reading ANY target code or artifact):
0. ROLE: If this skill NEVER reads target source (report, calibrate, reflect),
you are a FINDINGS-ONLY stage: skip steps 2-6; still read active_snapshot from
state for provenance/annotation; NEVER stop merely because a code root is unset.
1. Determine CODE_ROOT, in this priority order:
a. If --target_root is passed on THIS invocation, CODE_ROOT = --target_root.
It is AUTHORITATIVE and OVERRIDES SNAPSHOT_ROOT and the state fallback
(used when a caller hands you a prepared tree, e.g. a patched shadow).
b. Else if --snapshot_root (or SNAPSHOT_ROOT) is passed, use it.
c. Else read state_root/workspace/.mantis_state.json (state_root from
--state_root if passed, else ./workspace/... relative to the current dir)
-> active_snapshot.root / .snapshot_id / .snapshot_pinned.
d. Else (no arg AND no readable active_snapshot): CODE_ROOT = current directory,
treat snapshot_pinned = false (MODE-OFF). Do NOT stop.
2. SENTINEL CHECK (only if snapshot_pinned is true AND you did NOT take path 1a):
verify CODE_ROOT/.mantis_snapshot_id exists and equals SNAPSHOT_ID. If missing
or different -> STOP "snapshot sentinel mismatch". (A --target_root tree (1a) is
deliberately mutated and is sentinel-EXEMPT.)
3. PATH FIELDS:
- SNAPSHOT-RELATIVE (read under CODE_ROOT): code_paths entries; plan target_files
that are file paths. Strip ONLY a trailing ":<digits>". A code_paths entry
containing "://" is a URL/endpoint, NOT a file read. A code_paths entry that is
NOT of the form <existing-path>:<integer> is a non-source LOCATOR
(symbol/offset/endpoint): only check that the artifact/symbol exists; skip ALL
line-range and line-existence logic.
- STATE-RELATIVE (read/write under state_root/workspace, NEVER prefix CODE_ROOT):
kb_references, repro_file_path, reattack_file_path, helper scripts, report
files, and all state/findings JSON.
4. Never WRITE under CODE_ROOT when snapshot_pinned is true. Any command that
compiles, generates, or writes artifacts MUST run in a PRIVATE SHADOW copy
(mktemp -d from CODE_ROOT), never with cwd=CODE_ROOT. Read-only inspection may
cd into CODE_ROOT.
5. VCS-METADATA CARVE-OUT: history-log extraction and any VCS diff/blame command
run in the LIVE repository root (which still has .git/.hg/.repo), NOT CODE_ROOT
(the snapshot copy strips VCS metadata). Do NOT stop merely because CODE_ROOT
lacks .git/.hg/.repo.
6. Every shell command uses ABSOLUTE paths and sets its own working directory on
that call. Do NOT assume the working directory persists between calls.
说明
**当前轮次检查(防御性;约束性保证由
mantis-pipeline-adapter场景 2 中的 harness 提供):**如果存在active_snapshot,且active_snapshot.pass != state.pass_number,则将此快照视为本轮次的过期快照 — 停止并报告 "stale active_snapshot: pass mismatch",或降级为 HALT(snapshot_pinned实际上视为 false:没有权威判定,区块 B 为 NOT_MATCHED,复现状态为not_attempted)。这可捕获自定义 harness 在第 15 阶段递增轮次后保留active_snapshot、却没有重新固定快照的情况。参考 meta-agent 每轮都会重新固定快照,因此不会触发此检查。区块 B 本身无法检测此情况(它只检查snapshot_id,不检查pass)。
快照来源与 STALE-EVIDENCE 防护(机械性步骤;评分前执行):
P0. 从 state_root/workspace/.mantis_state.json(区块 A 步骤 0/1c)读取 active_snapshot({snapshot_id, snapshot_pinned, root})。如果该字段不存在,绝不要停止 — 校准是一个仅处理发现文件的阶段(区块 A 步骤 0)。
P1. 模式(整个运行过程采用单一决策——根据是否存在 active_snapshot 分支,3 状态模型):- 状态中不存在 active_snapshot(未请求 --sync——MODE-OFF = 今日默认行为)-> MODE = MODE-OFF。完全按照今日方式评分:按原样运行每项启发式,不计算 PROVENANCE,不发出 STALE_EVIDENCE,也不发出任何 HALT/PINNED 横幅。
(向后兼容的默认路径——逐字节保持今日行为。)-
active_snapshot 存在,且 snapshot_pinned 不严格等于 true(HALT 模式——代码树发生竞态或无法固定)-> MODE = HALT。SNAPSHOT_ID = active_snapshot.snapshot_id(一个 live: ID)。按照下方 P2 计算 PROVENANCE,并保守地触发 STALE-EVIDENCE 防护(就防护而言与 PINNED 相同),因为发现项的定位信息可能已过时。本轮禁止给出权威判定(VERIFIED_SECURE、failed_to_reproduce、DUPLICATE、FALSE_POSITIVE、NON_VIABLE)。- snapshot_pinned == true -> MODE = PINNED。
SNAPSHOT_ID = active_snapshot.snapshot_id。按照下文执行完整的 provenance 检查及 STALE-EVIDENCE 防护。
P2. 在 MODE = PINNED 或 HALT 时,使用 Block B 的比较规则,针对每个发现项 F 计算 PROVENANCE:- F.discovery_commit 缺失、为空或为字面值 "MIXED" -> NOT_MATCHED。- F.discovery_commit != SNAPSHOT_ID(精确字符串比较,不进行模糊匹配)-> NOT_MATCHED。- F.discovery_commit == SNAPSHOT_ID -> MATCHED。
P3. 当 MODE 为 PINNED 或 HALT,且满足以下任一条件时,针对 F 的某项启发式为 STALE:- PROVENANCE(F) == NOT_MATCHED,或 - 发现项的 code_paths 目标文件在 CODE_ROOT 下不存在。(按照 Block A 步骤 1 和 3 解析 CODE_ROOT;去掉末尾的 :<digits>;仅读取固定的根目录,绝不读取实时代码树。如果完全无法解析 CODE_ROOT,则将该文件视为不存在 -> STALE。)
P4. 当某项启发式对 F 属于 STALE 时,不要应用该启发式;保留保守的(调整前)评分;并确保字面标记 STALE_EVIDENCE 是 sanity_triage_applied 的第一个标记(仅添加一次,且位于任何 UNKNOWN 警告和任何已触发规则列表之前)。受保护的四项启发式及其确切的 STALE 处理方式如下:- 死代码 0.2 乘数(第 2 节“资产关键性与可达性”):不要应用 0.2 的缩减;使用原本应采用的乘数。- repro_failure(第 3 节规则):不要强制设为 LOW;设置 calibration_checklist.repro_failure.outcome = "UNKNOWN",并令 reason 以 "STALE_EVIDENCE: " 开头。- vague_code_paths(第 3 节规则):不要强制设为 LOW;设置 calibration_checklist.vague_code_paths.outcome = "UNKNOWN",并令 reason 以 "STALE_EVIDENCE: " 开头。- static_confirmation trace-lift(第 3 节规则,其“有效的外部堆栈跟踪/清理器……”例外):不要应用 trace-lift;保持静态 HIGH 上限生效(likelihood_score <= 3,0.8 Hazard 乘数,不得为 CRITICAL)。设置 calibration_checklist.static_confirmation.outcome = "APPLIES",并令 reason 以
"STALE_EVIDENCE: trace-lift suppressed; trace/crash-log may predate the active snapshot; " 开头。
P5. 非源代码发现项:如果发现项的 code_paths 条目是非源代码定位符(包含 "://",或不符合 <path>:<integer> 格式——参见 Block A 步骤 3:符号 / 偏移量 / 端点),则跳过该项的所有仅适用于源代码的启发式——死代码、文件路径/导入/调用层级暴露面推断、vague_code_paths 和静态跟踪重新检查——并根据发现项的声明元数据(attacker_position、privileges_required、production_viability、repro_status、威胁模型)评分。非源代码跳过不标记为 STALE_EVIDENCE(这是正常情况,不是漂移)。除非发现项/威胁模型另有声明,非源代码发现项的 inferred_exposure 默认为 "INTERNAL"(0.8)。
-
加载完整流水线状态:
- 读取
workspace/findings/目录中的所有 JSON 文件。由于流水线会在每个阶段向每个发现文件追加数据,这些文件记录了每项发现的完整历程(包括其id、复现状态和生产可行性)。 - 缺失字段的回退默认值: 如果某项发现缺少可行性或复现字段(例如链式发现),请在评分前应用以下回退默认值:
- 如果缺少
production_viability,则按"CONDITIONAL_VIABLE"处理。 - 如果缺少
repro_status,则按"not_attempted"处理。
- 如果缺少
- 快照来源(仅当 MODE 为 PINNED 或 HALT 时): 对每项发现,按照前置步骤 P2 计算 PROVENANCE(MATCHED / NOT_MATCHED),并记录在临时记录中。此值决定第 2 和第 3 节中的 STALE-EVIDENCE 处理方式(前置步骤 P3–P4)。在 MODE == MODE-OFF 时跳过此步骤——按当前方式评分。
- 从知识库读取
workspace/kb/THREAT_MODEL.md(如果存在),以评估组件暴露情况、信任边界、资产关键性以及任何自定义的校准覆盖项(例如应针对项目解除或自定义的特定威胁位置或上限)。 - 批处理: 如果需要校准的发现不止几项,请将任务拆分成若干批次(每批处理几项发现)。如果能够调用子 Agent,请将各批次委派给子 Agent 并行处理,然后汇总结果。**每个批次/子 Agent 只能检查固定快照:**传入
--snapshot_root=<active_snapshot.root>、--snapshot_id=<active_snapshot.snapshot_id>和--state_root=<workspace parent>,确保每个子 Agent 都通过 Block A 解析到相同的 CODE_ROOT。批次执行的任何代码检查(暴露情况推断、死代码检查、静态跟踪验证)都必须通过该 CODE_ROOT(固定副本)读取代码,绝不能读取实时目录树,并且必须遵守 STALE-EVIDENCE 防护(前置步骤 P3–P4)。无论如何,基于发现文件计算的字段(分数、优先级、历史记录标记)仍应从发现 JSON 中得出。
- 读取
-
计算风险分数(1-10): 对每个唯一的发现文件,按照以下公式组成部分,以矩阵形式计算实际技术风险分数,其中 Hazard = Impact + Likelihood:
- 影响(1–5): 使用 CIA 三要素(机密性、完整性、可用性)评估影响,同时严格考虑影响范围。
- 5:机密性遭受全面、系统性的损失(全面数据泄露、根加密密钥/HSM 主密钥泄露),或完整性遭受全面、系统性的损失(系统遭到入侵,例如,无特权攻击者可明确实现远程代码执行(RCE),且该攻击者原本并不处于能够执行代码的有效位置)。不得用于已经拥有代码执行权限的攻击者。
- 4:一个或多个方面遭受重大损失。包括系统性可用性损失(主要服务完全中断)或重大数据暴露。
- 3:中度损失(例如,部分数据暴露、系统暂时或部分中断)。
- 2:轻微损失(例如,轻微信息泄露、局部中断)。影响范围仅限于单个用户自己的数据的漏洞,影响评分不得高于 2。*例外:*如果该操作缺乏不可否认性(用户可以合理地否认实施欺诈的操作或将责任归咎于他人),或会触发影响其他用户/系统稳定性的副作用,则不应降低评分。
- 1:对 CIA 的影响可忽略,主要是表面问题。诸如“代码脆弱”“缺乏纵深防御”或纯理论性卫生问题等发现,影响评分必须为 1,确保其最高评级为低。
- **绕过安全控制(上调):**如果漏洞直接绕过核心安全控制(例如身份验证、授权、加密签名验证),或破坏库的主要安全目的(例如,旨在保护密钥集的库允许攻击者控制密钥集),则至少将影响评分上调至 4(若导致系统性入侵,则上调至 5),即使直接技术影响看似局部。
- 关于所需权限与横向移动的说明:
- 如果发现需要高权限(例如管理员权限、从管理员权限提升至超级管理员权限),或仅允许攻击者在已经入侵的状态下于内部组件之间横向移动/跳转,则其单项影响评分最高为 2;但若利用可逃逸容器边界、进入宿主节点或实现跨租户权限提升,则不受此限制。
- 如果发现需要低权限(例如普通已通过身份验证的用户),则其单项影响评分最高为 3;但若会导致其他租户/用户遭受系统性入侵,或直接绕过核心安全控制/破坏库的主要目的,则可评得更高。
- 这些上限适用于单项发现。如果链式利用器成功将其串联为 Exploit Chain(Super Finding),则应根据该链入口点(初始步骤)所需的权限级别评估整条链。
- **可能性(1–5):**根据已证实的可利用性,而非理论难度,评估事件发生概率。
- 5:正在野外遭到利用,或 Agent 成功生成了可用的武器化利用代码(而不只是单元测试)。
- 4:存在公开的概念验证(PoC),或 Agent 生成了高度可信但仅部分武器化的利用代码。
- 3:没有可用的利用代码,但攻击途径很容易自动化。
- 2:理论上可能,且非常复杂(需要本地访问、严格的时序条件)。
- 1:纯理论风险,没有已知的利用路径。
- **实际可达性修正项:**确定基础可能性后,如果利用路径依赖罕见或非默认的使用模式,则将
likelihood_score降低 1 或 2(但不得低于 1.0)。以下情况适用:- 特定受污染参数只有在罕见 API 调用、不常见的配置字段或现实中很少处理的数据格式中,才会由攻击者输入填充。
- 漏洞需要实际上很少启用的非标准或仅管理员可用配置。
- 上下文乘数(0.1–1.0):
- 如果
status为 FALSE_POSITIVE 或 NEEDS_RESEARCH,或production_viability为 NON_VIABLE:完全丢弃该发现。不要为其评分,也不要使用校准数据更新其文件。 - 如果
production_viability为 VIABLE、CONDITIONAL_VIABLE 或 SAMPLE_OR_TEST:- 网络/信任暴露:
- 如果发现位于暴露接口/信任边界内(不可信输入可直接访问):1.0。
- 如果位于接受半可信解析数据的内部组件中:0.8。
- 如果深藏于特权/可信区域中:0.5。
- **威胁模型缺失/不完整时的推断:**如果
workspace/kb/THREAT_MODEL.md不存在或未提及该组件:- 分析文件路径、导入和调用方层级,以推断暴露程度(例如,公共 API 与内部辅助函数)。**只能读取固定的 CODE_ROOT(Block A),切勿读取实时文件树。非源码(前言 P5):对于非源码 LOCATOR 发现,跳过此文件路径/导入/调用方分析——默认将
inferred_exposure设为"INTERNAL"(0.8),除非发现或威胁模型另有说明。**当 MODE 为 PINNED 或 HALT,且发现为 NOT_MATCHED 或其code_paths文件在 CODE_ROOT 下不存在时,切勿根据对实时文件的重新检查降低暴露乘数,低于已声明/默认值(保留较保守的较高乘数)。 - 默认将暴露乘数设为 0.8(内部),并将
inferred_exposure设为"INTERNAL",除非有明确证据表明其直接暴露于外部(EXPOSED)或深层隔离(PRIVILEGED)。本地 SUID/LPE 二进制文件默认应设为"INTERNAL"暴露。 - 如果发现描述、历史记录或评审者的推理表明该组件“很少暴露”“仅供内部使用”或“不太可能被攻击者触达”,则将暴露乘数降低至 0.5 或更低。
- 分析文件路径、导入和调用方层级,以推断暴露程度(例如,公共 API 与内部辅助函数)。**只能读取固定的 CODE_ROOT(Block A),切勿读取实时文件树。非源码(前言 P5):对于非源码 LOCATOR 发现,跳过此文件路径/导入/调用方分析——默认将
- 映射暴露程度与攻击者位置元数据:
- 根据网络/信任暴露乘数确定
inferred_exposure:- 乘数 1.0(暴露接口)→
"EXPOSED" - 乘数 0.8(内部组件)→
"INTERNAL" - 乘数 0.5(特权/可信区域)→
"PRIVILEGED"
- 乘数 1.0(暴露接口)→
- 评估攻击者位置(在发现中声明):
- 从发现 JSON 中读取
attacker_position。 - 根据边界判定,而非传输方式:
attacker_position必须表示第一个不可信主体(最终的人类攻击者或外部威胁行为者)要到达接口必须跨越的最外层边界。不要依据传输协议(例如 HTTP、gRPC、IPC)或直接协议对端来判定。- **追溯至不可信行为者:**如果与接口交互的直接对端是按设计可信的组件(例如内部代理、网关、消息队列或主控器),必须沿数据流追溯,找出不可信行为者首次进入系统时跨越的最外层边界。
- 如果接口绑定到
localhost或使用本地 IPC(Unix 套接字、管道、共享内存),则位置为"LOCAL",即使底层使用 HTTP/TCP 也是如此。 - 如果接口只能在专用网络(VPC、企业网络、家庭局域网、本地网络、内部集群控制平面)内访问,则位置为
"INTERNAL_NETWORK"(如果仅限 Pod 间访问,则为"IN_CLUSTER"),即使它是 Web 服务也是如此。 - 只有当接口可从公共互联网直接访问时,位置才为
"EXTERNAL"。 - 如果接口需要物理接触、硬件交互(例如 JTAG、调试探针、芯片开封)或本地无线近距离接触(例如 NFC、Bluetooth),则无论使用何种协议,位置都必须为
"PHYSICAL_TEMPORARY"或"PHYSICAL_LONG_TERM"。
- 规范化自由文本:如果值存在,但为不完全匹配某个有效枚举值的自由文本字符串(例如旧式表述),则必须将其规范化为最接近的有效枚举值,映射如下:
- 匹配
"authenticated <role>"、"customer with"、"tenant <role>"、公共产品中的"Fitbit user"等表述 →"EXTERNAL"(privileges_required: "LOW")。 - 匹配
"local user"、"local shell"、"local access"等表述 →"LOCAL"。 - 匹配
"peer <role> in same job/cluster/pod"、"co-tenant"、"in-cluster (Kubernetes/container-orchestrator) workload"、"NCCL peer rank"等表述 →"IN_CLUSTER"。 - 匹配
"malicious dependency"、"upstream package"、"build-time"、"CI pipeline"等表述 →"SUPPLY_CHAIN"。 - 匹配
"host hypervisor"、"host OS"、"hypervisor access"等表述 →"HOST_SYSTEM"。 - 匹配
"physical access"、"fault injection"等表述 → 根据边界判定为"PHYSICAL_LONG_TERM"或"PHYSICAL_TEMPORARY"。
- 匹配
- 如果该值完全缺失,则使用以下后备准则推断(并记录警告,建议提前声明该值):
"EXTERNAL":组件为"EXPOSED",或这是针对公共门户的身份验证绕过。"LOCAL":这是本地权限提升(LPE)或 SUID 利用。"IN_CLUSTER":攻击目标是从 Pod 发起的集群内部基础设施攻击(CSI/CNI)。"HOST_SYSTEM":攻击者是虚拟机监控程序、宿主 OS,或是攻击其所承载软件(客户机驱动程序、Enclave 运行时、固件目标)的模拟/物理设备。此枚举严格用于从外到内的方向。反向方向——从客户机到宿主机(VM 逃逸)、从沙箱到外部、从 Enclave 到宿主机,或从受限进程到容器——必须归类为"LOCAL"(Kubernetes Pod 到节点的情况为"IN_CLUSTER";KVM/虚拟机监控程序客户机攻击其宿主机的情况为"LOCAL"),绝不能归类为"HOST_SYSTEM"。"PHYSICAL_LONG_TERM"/"PHYSICAL_TEMPORARY":如果漏洞描述、标题或代码路径表明存在硬件故障注入、侧信道、恶意女佣攻击或 USB 物理访问。"SUPPLY_CHAIN":适用于需要在构建时修改依赖项的情况。"INTERNAL_NETWORK":其他内部组件的默认后备值。
- 使暴露程度与位置一致:
- 如果
attacker_position为"LOCAL"或"IN_CLUSTER",则必须将inferred_exposure判定为"INTERNAL"(使用 0.8 乘数),即使易受攻击的代码路径位于威胁模型中映射为"EXPOSED"的文件夹内;但如果利用明确逃逸容器边界、进入宿主节点,则不受此限制。 - 如果
attacker_position为"INTERNAL_NETWORK",则必须将inferred_exposure判定为不高于"INTERNAL"(使用 0.8 或更低的乘数),即使组件在威胁模型中映射为"EXPOSED";因为该接口无法从公共互联网直接访问。 - 如果
attacker_position为"EXTERNAL",则必须将inferred_exposure判定为"EXPOSED"(使用 1.0 乘数),即使组件在威胁模型中映射为"INTERNAL"或"PRIVILEGED"(这反映了不可信的外部输入可以到达该组件)。
- 如果
- 从发现 JSON 中读取
- 根据网络/信任暴露乘数确定
- 资产关键性与可达性:
- 如果威胁模型表明该组件处理高价值数据(例如 PII、核心机密),则保持较高乘数。
- 如果影响的是低价值目标(例如内部分析数据、沙箱测试数据),则降低乘数(例如降至 0.5)。
- **仅影响可用性的上下文:**如果发现仅影响可用性(DoS),请检查威胁模型中的组件
availability_tier(如果缺失,默认为 STANDARD):LOW_CRITICALITY:将乘数降至 0.5。STANDARD:将乘数降至 0.8。CRITICAL:保持乘数为 1.0。
- 如果静态/动态分析证明易受攻击的代码实际上是“死代码”(在运行时执行路径中从未调用),则将乘数大幅降至 0.2。陈旧证据保护措施(前言 P3–P4):如果发现为 STALE(MODE 为 PINNED 或 HALT,且该发现与活动快照 NOT_MATCHED,
code_paths文件在固定的 CODE_ROOT 下不存在),则不得应用此 0.2 降低项——漂移的代码可能会被错误地判定为“未调用”;应保留较高乘数,并将STALE_EVIDENCE设为sanity_triage_applied的首个令牌。执行的任何死代码分析都必须检查固定的 CODE_ROOT,绝不能检查实时文件树。**非源码(前言 P5):**对于非源码 LOCATOR 发现,完全跳过此启发式规则。
- 用户交互:
- 如果
user_interaction为 REQUIRED(例如 CSRF、点击劫持,或说服用户打开恶意文件),则对上下文乘数应用 0.7 乘数(例如,如果暴露程度为内部(0.8),且需要用户交互,则组合乘数为 0.8 * 0.7 = 0.56)。这样可确保此类发现的评级低于严重级别阈值。
- 如果
- 网络/信任暴露:
- 如果
production_viability为 SAMPLE_OR_TEST:- 对上下文乘数应用 0.4 缩放系数(即将当前上下文乘数乘以 0.4),使示例代码中的严重错误通常落入中等评级,而非高危或严重评级。此缩放系数必须与其他修正项累积应用。不要直接将上下文乘数设为
0.4,因为如果组件的暴露程度或死代码状态已计算为低于0.4(例如0.2),这样做会错误地提高乘数。 - 在
executive_summary中明确说明这不是生产环境中的错误。建议必须着重修复示例/测试,避免开发者将不安全的模式复制到生产代码中。
- 对上下文乘数应用 0.4 缩放系数(即将当前上下文乘数乘以 0.4),使示例代码中的严重错误通常落入中等评级,而非高危或严重评级。此缩放系数必须与其他修正项累积应用。不要直接将上下文乘数设为
- 如果
production_viability为 CONDITIONAL_VIABLE:- 对上下文乘数应用 0.7 缩放系数(即将当前上下文乘数乘以 0.7),以反映该漏洞需要特定的非默认配置、编译器标志或启用断言才能利用。此缩放系数必须与其他修正项(例如用户交互)累积应用。不要直接将上下文乘数设为
0.7,因为如果组件的暴露程度已经较深/隔离(0.5),这样做会错误地提高乘数。 - 在
executive_summary中记录其可利用所需的具体条件。 最终分数(危害)=(影响 + 可能性) 倍数*(上限为 10.0)。
- 对上下文乘数应用 0.7 缩放系数(即将当前上下文乘数乘以 0.7),以反映该漏洞需要特定的非默认配置、编译器标志或启用断言才能利用。此缩放系数必须与其他修正项(例如用户交互)累积应用。不要直接将上下文乘数设为
- 如果
关于愤慨的说明: 在推理中,请对更广泛的公式 风险 = 危害 + 愤慨 发表评论,其中应考虑“愤慨风险”(例如声誉受损、用户情绪造成的负面影响)。最终数值分数中不要包含愤慨因素。
- 影响(1–5): 使用 CIA 三要素(机密性、完整性、可用性)评估影响,同时严格考虑影响范围。
-
关键合理性分流(降低等级与限制发现项): 在确定最终优先级之前,请对发现项的质量、上下文和累积证据进行第二层合理性检查。
核心原则——边际能力: 发现项的最终严重性和优先级,严格受攻击者相对于其前置位置所获得的边际能力限制。如果利用漏洞并未让攻击者获得超出其起始位置固有能力(或通过合法途径已拥有的能力)的显著新控制权、访问权限或能力,则必须限制该发现项的等级或将其降级。
27 条校准合理性规则的完整详细定义存储在参考目录的 校准规则 中。你必须根据其中列出的 27 条规则逐一评估每个发现项。
检查
THREAT_MODEL.md是否定义了任何Calibration Overrides(例如LIFT_CAP: PHYSICAL_LONG_TERM)。如果某个发现项的位置或组件存在覆盖规则,则该规则优先适用,并解除相应的等级上限。否则,参考目录中指定的上限和降级规则(以及边际能力原则的一般应用)将覆盖第 2 节中计算的任何升级(包括安全控制绕过升级)。你还应应用这一一般原则,对其他边际能力较低的发现项进行限级或降级。重要:上限(HIGH 或 MEDIUM)只限制允许的最高分数/优先级,不得提高较低的分数/优先级(例如,分数为 5.0 的发现项自然属于 MEDIUM,即使其受 HIGH 上限限制,也必须保持为 MEDIUM)。优先级与 UNKNOWN 规则策略:
- STALE-EVIDENCE 优先级(前言 P3–P4): 当 MODE 为 PINNED 或 HALT,且某项发现为 STALE(与活动快照不匹配,或其
code_paths文件在固定的 CODE_ROOT 下不存在)时,不得使用以下规则根据实时重新检查降低或提高分数:repro_failure(不得强制为 LOW)、vague_code_paths(不得强制为 LOW),以及static_confirmationtrace-lift 例外(不得将过时的跟踪记录/sanitizer/崩溃日志视为实时复现——保留静态 HIGH 上限)。也不得应用第 2 节的死代码 0.2 倍数(见第 2 节)。保留保守分数,并将字面标记STALE_EVIDENCE前置为sanity_triage_applied的第一个标记(位于任何Incomplete Calibration (UNKNOWN: …)警告和已触发规则列表之前)。按照前言 P4 的规定,在calibration_checklist中记录受保护的规则(repro_failure/vague_code_paths->UNKNOWN,并附带STALE_EVIDENCE:原因;static_confirmation->APPLIES,并附带说明 trace-lift 已被抑制的STALE_EVIDENCE:原因)。在 MODE == MODE-OFF 时,本条不生效(按当前方式评分)。 - 评估所有规则。如果多个上限适用,则采用限制最严格的一项(强制为 LOW > 上限为 MEDIUM > 上限为 HIGH)。
- UNKNOWN 结果的策略: 如果某项规则的评估结果为
UNKNOWN,则不应用上限或降级(保守评分;保留较高的计算分数/优先级)。但是,将警告前置到"sanity_triage_applied"字符串中,以标记整体校准尚未完成/为临时结果:"Incomplete Calibration (UNKNOWN: <rule_name>)"(如果存在多个 UNKNOWN,则以分号分隔列出多个警告)。这表示需要人工审核以确定规则状态。 - 将每条成功触发/应用的规则记录在
sanity_triage_applied中,以分号分隔并按限制严格程度从高到低排列(例如"Local Attack Vector; Internal/Nested");如果存在任何 UNKNOWN 警告,则追加在这些警告之后,以便完整审计实际生效的上限。
- STALE-EVIDENCE 优先级(前言 P3–P4): 当 MODE 为 PINNED 或 HALT,且某项发现为 STALE(与活动快照不匹配,或其
-
确定优先级:
- CRITICAL(8.0 - 10.0): 需要立即处理。危险性极高(例如影响和可能性都很高)。仅当未特权攻击者(
privileges_required为 NONE)在尚未处于能够有效破坏系统的位置时,可以造成明确的 RCE(或等同的全面损失),且user_interaction为 NONE(零点击)时,才能使用此级别。此规则为绝对规则:即使某项发现(例如 CSI 主机逃逸)的第 3 节上限已解除,如果入口处需要 HIGH 权限,也不得评为 CRITICAL,必须将上限设为 HIGH(7.9)。仅影响可用性的发现(DoS)不得评为 CRITICAL,除非威胁模型明确记录availability_tier为CRITICAL,且没有自动恢复机制(例如自动重启、负载均衡器故障转移)缓解其影响。 - HIGH(6.0 - 7.9): 高优先级。危险性显著,需要尽快解决。
- MEDIUM(3.0 - 5.9): 常规优先级。危险性中等,可安排处理。
- LOW(0.1 - 2.9): 低优先级。危险性极低。任何属于“代码脆弱”、纯粹属于卫生/纵深防御问题,或仅影响单个用户自身数据的发现,无论计算分数如何,都必须将优先级上限设为 LOW(除非适用缺乏不可否认性或存在更广泛副作用的例外)。
- CRITICAL(8.0 - 10.0): 需要立即处理。危险性极高(例如影响和可能性都很高)。仅当未特权攻击者(
-
令牌优化的文件更新: 为尽量减少大模型输出的令牌,请勿在输出中重新输出或手动重写整个 JSON 对象。 而是要在首次更新发现项时编写一个可复用的辅助脚本(例如,
workspace/helpers/append_calibrate.py)。对于之后的所有发现项,请勿重新生成脚本;只需使用新参数执行现有辅助脚本,将所需字段追加到workspace/findings/<id>.json。- 辅助脚本版本标记(必需)。
append_calibrate.py的第一行必须是完全一致的注释# MANTIS_HELPER_VERSION = 2。重新使用现有辅助脚本前,请读取其第一行:如果文件不存在,或第一行与# MANTIS_HELPER_VERSION = 2不完全一致(标记缺失或整数不同),请从头重新生成辅助脚本(旧版辅助脚本会静默丢弃新的snapshot历史记录字段,并且无法处理STALE_EVIDENCE)。重新生成的辅助脚本必须能够将snapshot键写入追加的history条目,并将STALE_EVIDENCE添加到sanity_triage_applied的首位。辅助脚本必须与 STATE 相关(workspace/helpers/…,Block A 第 3 步)——绝不可将其写入 CODE_ROOT。
除现有核心发现数据外,还要明确追加以下字段,以显示矩阵细分情况:
-
"impact_score"(1-5) -
"likelihood_score"(1-5) -
"availability_tier"(CRITICAL、STANDARD、LOW_CRITICALITY 或 null) -
"inferred_exposure"(EXPOSED、INTERNAL 或 PRIVILEGED) -
"attacker_position"(保留输入中的值;如果缺失,则使用回退推断填充) -
"mantis_risk_score"(最终 Hazard 分数) -
"priority"(CRITICAL、HIGH、MEDIUM、LOW) -
"sanity_triage_applied"(以分号分隔的列表,或 null)。排序顺序: 如果发现项为 STALE(序言 P4),则STALE_EVIDENCE排在首位;然后是所有Incomplete Calibration (UNKNOWN: <rule>)警告;最后是触发的 Section 3 规则,按限制性从高到低排列。示例:"STALE_EVIDENCE; Incomplete Calibration (UNKNOWN: physical_long_term); Local Attack Vector"。 -
"calibration_checklist"对象,包含对全部 27 项 sanity cap 的评估。对象中的每个键都映射到同名的 sanity cap 规则:{ "repro_failure": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "unreachable_inputs": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "third_party_reachability": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "minor_config_hygiene": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "non_security_critical": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "vague_code_paths": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "unreliable_triggers": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "prerequisite_shell": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "physical_long_term": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "trusted_controller_zero_delta": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "standard_host_attacks": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "static_confirmation": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "strict_xss": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "internal_nested": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "probabilistic_llm": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "supply_chain_prerequisites": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "non_default_config": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "confidential_computing_host": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "trusted_controller_critical_bypass": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "local_attack_vector": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "self_contained_blast": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "rarely_exposed": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "equivalent_primitives": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "documented_insecure_config": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "physical_temporary": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "high_privilege_external": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" }, "trusted_controller_standard_bypass": { "outcome": "APPLIES" | "DOES_NOT_APPLY" | "UNKNOWN", "reason": "<string>" } }对于每条规则,
outcome必须设置为:"APPLIES":如果合理性上限规则适用于(触发)该发现项, 对其评分/优先级进行封顶或降级。必须提供详细的reason字符串。"DOES_NOT_APPLY":如果合理性上限规则不适用。reason字段为可选,可以省略以优化 token。"UNKNOWN":如果尚未解决。必须提供详细的reason字符串。
为向后兼容,schema 也允许
"fires": <bool>(仅在fires为true时才必须提供reason),但首选新的"outcome"格式。 -
"outrage_commentary"(你对愤怒系数的推理) -
"executive_summary" -
向
"history"数组添加一个条目:{ "stage": "calibrate", "action": "calibrated", "details": "计算出的风险评分为 [score],优先级为 [priority]。[ STALE_EVIDENCE: 评分时未通过重新检查实时代码来确认。]", "pass_number": <current_pass_number>, "snapshot": "<active_snapshot.snapshot_id, or omit in MODE-OFF>", "timestamp": "<current_iso8601_timestamp>" }
- 辅助脚本版本标记(必需)。
将更新保存到各个发现项文件中。完成后,通知用户。