关于 mantis-critic
mantis-critic 是用于安全审查的技能,会独立核验已报告的问题在优化后的生产构建中是否仍可触发。它通过快照和源码检查处理代码漂移或缺失,避免据此判定问题不可行。
主要功能
- 01核验生产构建中的可行性
- 02独立检查源码路径
- 03检测快照漂移与行号越界
- 04检查威胁模型中的部署意图
- 05幂等更新问题与学习记录
适用场景
- 01筛除仅存在于调试或测试路径的问题
- 02根据固定代码快照重新评估问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ google/ mantis --skill mantis-critic安装后在 Claude Code 中输入/mantis-critic确认已加载。
详细介绍
Critic(/mantis-critic)
系统目标
生产环境可行性专家。筛选已验证的安全发现,确认它们在标准发布和生产配置中是否仍可触发。
命令定义
- 命令:
/mantis-critic [--target_root=<path>] [--snapshot_root=<path>] [--snapshot_id=<id>] [--state_root=<path>] - **说明:**评估发现问题在生产环境中的可行性,过滤仅限调试的功能和断言陷阱。
- 参数:
--target_root:目标代码库根目录的权威路径。覆盖所有其他定位器来源,且不受哨兵检查限制(Block A 路径 1a)。默认为未设置。--snapshot_root:本轮固定的不可变快照副本路径(又称SNAPSHOT_ROOT)。当--target_root未设置时,作为CODE_ROOT使用(Block A 路径 1b)。--snapshot_id:协调器为本轮计算的SNAPSHOT_ID。用于 Block A 哨兵检查,以及 Step 3 中针对每项发现的 Block B 漂移比较。如果省略,则回退到状态中的active_snapshot.snapshot_id。--state_root:包含workspace/的 Mantis 状态目录根路径(默认为.)。本文件中的所有workspace/...路径都相对于--state_root解析;默认值为.时,这与当前的workspace/相同。
输入/输出约定
- 读取:
workspace/findings/(加载所有发现,不论其状态如何;同时读取每项发现可选的discovery_commit,用于逐项检查快照匹配)。workspace/kb/THREAT_MODEL.md(若存在,用于检查部署意图以及知识库记录的kb_snapshot_id)。workspace/.mantis_state.json(用于跟踪当前循环轮次,并读取active_snapshot.{root,snapshot_id,snapshot_pinned}以解析定位器和来源信息)。- 已解析的
CODE_ROOT下的目标源代码文件(若snapshot_pinned,则为固定的快照根目录),以及code_paths中带上下文偏移的位置/行。
- 写入:
- 原位更新发现(设置
"production_viability"、"critic_reasoning"并追加历史记录)。 - 追加内容到
workspace/learnings.jsonl。
- 原位更新发现(设置
- 前置条件:
workspace/findings/中必须存在发现。
- 幂等性保证:
- 原位覆盖可行性字段。必须检查历史数组中是否已记录当前轮次的 critic 条目,并检查
workspace/learnings.jsonl,确保在相同输入下重新运行时不会写入重复记录。
- 原位覆盖可行性字段。必须检查历史数组中是否已记录当前轮次的 critic 条目,并检查
说明
评估已验证的发现,判断它们是否构成已编译、优化后的发布版本中的可利用安全漏洞。采取高度怀疑、对抗性的立场。不要相信前序阶段的推理。独立重新验证代码路径,明确证实或否定其在生产环境中的可行性。
定位器解析(首先执行)
Critic 属于代码阅读阶段(会检查目标源代码),因此并非仅处理发现的阶段:执行 Block A 的全部内容。在加载发现之前,先按 Block A 解析 CODE_ROOT 和哨兵。
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-adapterScenario 2 中的执行框架提供):**如果存在active_snapshot,且active_snapshot.pass != state.pass_number,则将此快照视为本轮的过期快照——停止并报告“stale active_snapshot: pass mismatch”,或降级为 HALT(snapshot_pinned实际视为 false:不提供权威判定,Block B 为 NOT_MATCHED,重现状态为not_attempted)。这可捕获在 Stage 15 增加轮次后保留active_snapshot、却未重新固定快照的自定义执行框架。参考元 Agent 每轮都会重新固定快照,因此不会触发此检查。Block B 本身无法检测此问题(它只检查snapshot_id,不检查pass)。
此阶段的 SNAPSHOT_ID: 如果提供了 --snapshot_id,则将其值作为 SNAPSHOT_ID;否则使用 workspace/.mantis_state.json 中的 active_snapshot.snapshot_id。如果两者都不存在(没有 --snapshot_id,且状态中没有 active_snapshot),或者 Block A 通过路径 1d(无参数,当前目录)解析出 CODE_ROOT,则 SNAPSHOT_ID 不可用(MODE-OFF = 今天的默认模式):将 Step 3 中的每项 Block B 检查都视为 NOT_MATCHED,并将 Step 2 中的 KB 新鲜度门槛视为 FAILED。不要停止;按下文说明降级处理。当 active_snapshot 存在,但 snapshot_pinned 为 false(HALT 模式)时,SNAPSHOT_ID 是记录的 live: ID,且可用 — Block B 仍返回 NOT_MATCHED(因为 snapshot_pinned 为 false),但下文的 Step-3c“MODE-OFF 例外”不适用:NOT_MATCHED 结果应视为漂移 →
CONDITIONAL_VIABLE,而非 NON_VIABLE(后者会被 calibrate 丢弃)。
按以下步骤执行评审评估:
-
加载发现项: 读取
workspace/findings/目录中的 JSON 文件。无论发现项的状态如何(包括"VALID"、"FALSE_POSITIVE"、"PROVISIONALLY_VALID"和"NEEDS_RESEARCH"),都必须全部加载,以便处理或记录到长期记忆中。如果没有任何发现项,请通知用户。 -
评估全局仓库意图(受 KB 新鲜度门槛约束): 读取
workspace/kb/THREAT_MODEL.md(如果存在)。检查 Deployment Intent 部分。KB 新鲜度门槛 — 执行任何批量统一标记前必须通过(3 状态规则): 确定 KB 所依据的快照。从以下来源读取(按顺序尝试,采用第一个匹配项):
workspace/kb/THREAT_MODEL.md第一行中的字面标记KB_SNAPSHOT:(threat-model 会将其写为裸标题;architecture 会在每个 KB 文件中写入带注释的 ``。对于 architecture 文件,扫描注释中的KB_SNAPSHOT:子串。不要查找kb_snapshot_id:或Snapshot:— 这些标记从未写入,因此门槛永远不会匹配)。- 否则,使用
workspace/.mantis_state.json中的kb_snapshot_id值(architecture 会在其状态标记步骤中写入该值)。 - 否则,使用
""(没有先前的 KB 来源记录)。批量统一标记受以下规则约束:
- MODE-OFF(状态中没有
active_snapshot— 没有--sync):完全跳过新鲜度门槛。允许像今天一样批量统一标记SAMPLE_OR_TEST(与今天的行为逐字节一致)——KB 是依据实时树构建的,且没有快照可供比较。 - HALT 或 PINNED(
active_snapshot存在):只有记录的KB_SNAPSHOT:(或kb_snapshot_id)存在且与上文 Locator Resolution 中解析出的当前SNAPSHOT_ID逐字节相等(不进行模糊比较)时,才允许批量统一标记。如果该值缺失、为空或与SNAPSHOT_ID不相等,则不得批量统一标记:完全跳过此批量操作,并在 Step 3-5 中逐项评估每个发现项。
只有在新鲜度门槛通过(或在 MODE-OFF 下跳过门槛)时:如果 threat model 明确指出整个仓库专门用于教程、示例项目或测试套件(例如
Intent: SAMPLE_OR_TEST_ONLY),则必须将所有发现项标记为SAMPLE_OR_TEST,无论它们位于文件结构中的何处,并跳过其余逐项可行性检查。 -
获取目标代码片段(与快照匹配): 对于每个
status为"VALID"或"PROVISIONALLY_VALID"的发现项(如果发现项状态为"FALSE_POSITIVE"或"NEEDS_RESEARCH",则跳过此步骤及后续评估步骤): a. 根据发现项的code_paths定位目标文件,遵循 Block A 第 3 步:code_paths是相对于 SNAPSHOT 的,因此请在 CODE_ROOT 下读取。 去掉末尾的:<digits>以获取行号;://表示 URL,而非文件;任何不符合<path>:<int>格式的条目都是非源码 LOCATOR——仅检查是否存在,不进行行号逻辑处理。b. 快照匹配检查(Block B): 将该发现项的
discovery_commit与当前SNAPSHOT_ID进行比较,计算 MATCHED / NOT_MATCHED。SNAPSHOT MATCH CHECK for finding F (decides MATCHED vs NOT_MATCHED): 1. If snapshot_pinned is false -> NOT_MATCHED. Stop. 2. Read F.discovery_commit: - missing OR empty OR the literal "MIXED" -> NOT_MATCHED. - not exactly equal to SNAPSHOT_ID -> NOT_MATCHED. - exactly equal to SNAPSHOT_ID -> MATCHED. There is no other route to MATCHED; never fuzzy-compare. The global "default the field and proceed" backward-compat rule does NOT apply to discovery_commit: absent = NOT_MATCHED. (There is NO separate "dirty" gate: a dirty tree's SNAPSHOT_ID already embeds the working-tree content hash, so within-pass findings MATCH and cross-pass bare-commit findings do not.)c. 漂移 / 文件缺失 / 超出范围防护(故障安全——绝不标记为 NON_VIABLE): 如果 Block B 的结果为 NOT_MATCHED,或解析出的目标文件在 CODE_ROOT 下不存在,或指定行号超出文件末尾(超出范围),则不得对该发现项 执行特定领域的可行性分析(步骤 4-5),也不得将其标记为
NON_VIABLE(文件缺失不代表死代码;mantis-calibrate会丢弃NON_VIABLE值)。例外情况(仅限 MODE-OFF——没有 active_snapshot): 如果 SNAPSHOT_ID 不可用(MODE-OFF:状态中没有
active_snapshot,且没有--snapshot_id), 并且 NOT_MATCHED 的唯一原因是 SNAPSHOT_ID 缺失 / 不可用(而非文件缺失或 行号超出范围),则将其视为“无法比较”,并继续进行常规评估(步骤 3d)。这会保留 非同步运行的现有行为。在 HALT 模式下(存在active_snapshot,snapshot_pinned=false),此例外不适用:Block B 的结果为 NOT_MATCHED,且该发现项属于漂移 → CONDITIONAL_VIABLE(下方的“否则” 分支),绝不能标记为 NON_VIABLE(calibrate 会丢弃此值)。无论是否固定快照 或处于何种模式,文件缺失和行号超出范围的情况仍会强制标记为 CONDITIONAL_VIABLE。否则(漂移、文件缺失或超出范围): 将
production_viability设为CONDITIONAL_VIABLE,并在critic_reasoning中写入说明原因的漂移备注,例如:"Snapshot drift: discovery_commit=<disc> != active SNAPSHOT_ID=<id> (or the target file/line is no longer present at the pinned snapshot); could not re-verify viability, defaulting to CONDITIONAL_VIABLE (conservative)."然后通过步骤 6 记录更新,并继续处理下一个发现项。(此发现项仍会在步骤 7 中以CONDITIONAL_VIABLE状态记录到长期记忆。)d. 匹配、文件存在且行号在范围内: 从 CODE_ROOT 读取目标文件,并读取指定 行号前至少 15 行上下文和后至少 15 行上下文。此定向窗口对于分析周边结构和宏定义是必要的。 此外,检查
repro_hints和history,查找mantis-reproduce记录的实证执行遥测 (例如build_profile、sanitizers_used、assertions_disabled、ingress_blocked)。使用这些 实证执行遥测来佐证发布构建的可行性。继续执行步骤 4-5。 -
评估特定领域的可行性约束:
- 对于内存安全缺陷: 找到受影响缓冲区的分配来源。确定分配时是否带有安全余量或尾部填充。如果越界访问仍处于物理填充范围内,则将其标记为 NON_VIABLE。
- 对于逻辑与授权缺陷: 确认存在缺陷的逻辑或被绕过的端点在标准生产部署中确实可访问。如果缺陷依赖于仅用于调试的后门、模拟身份验证提供程序或仅供测试使用的路由,则将其标记为 NON_VIABLE。
-
确定可行性状态: 为发现项分配以下其中一种可行性 状态,以确保我们能正确设置优先级:
NON_VIABLE:该缺陷在生产环境中不可触发,或已在编译时移除。 包括:- **禁用断言(内存缺陷):**依赖标准
assert()、debug_abort()或仅用于开发的 panic 来触发崩溃/DoS 状态的错误;在NDEBUG移除这些断言后,代码会安全返回。 - **仅限调试的功能:**使用调试标志(例如
#ifdef DEBUG)进行条件编译。 - **受到环境控制阻止:**受到标准且不可配置的生产环境控制阻止(例如操作系统级权限、内核级沙箱、只读文件系统),且无法绕过。
- **禁用断言(内存缺陷):**依赖标准
SAMPLE_OR_TEST:问题存在于示例代码、测试套件、模糊测试框架或验证框架中。CONDITIONAL_VIABLE:只有在特定的非默认配置、可选编译器标志或自定义加固选项下,缺陷才可被利用;这些条件可能因生产环境而异。VIABLE:该缺陷在标准发布版/生产构建中完全可触发。
-
**令牌优化的文件更新:**为尽量减少 LLM 输出令牌,**请勿在输出中重新生成或手动改写整个 JSON 对象。**而应使用就地编辑工具(例如用首选语言编写的短脚本或
jq),以编程方式将新字段追加到现有的workspace/findings/<id>.json文件中。必须向现有对象追加以下内容:
"production_viability"字段("VIABLE"、"NON_VIABLE"、"SAMPLE_OR_TEST"或"CONDITIONAL_VIABLE")。- 说明评估理由的
"critic_reasoning"字段。 - 在
"history"数组中添加一项:
{ "stage": "critic", "action": "evaluated", "details": "Determined production viability as [VIABLE/NON_VIABLE/SAMPLE_OR_TEST/CONDITIONAL_VIABLE] because [reason]", "pass_number": <current_pass_number>, "snapshot": "<SNAPSHOT_ID>", "timestamp": "<current_iso8601_timestamp>" }将
"snapshot"设为 Locator Resolution 中解析出的SNAPSHOT_ID。如果SNAPSHOT_ID为 UNAVAILABLE(MODE-OFF),则将其设为""(或省略该键)。请勿伪造 ID。 -
**追加到长期记忆:**对于加载的每条发现(包括
NON_VIABLE、SAMPLE_OR_TEST、CONDITIONAL_VIABLE、FALSE_POSITIVE和NEEDS_RESEARCH),都要以追加模式向名为workspace/learnings.jsonl的工作区数据库文件追加一行结构化 JSON。这样可以记住各次运行的验证结果,帮助策略制定者避免重复扫描。- 记忆条目格式:
{"title": "[security_flaw_title]", "code_paths": ["[path1:line1]"], "status": "[VIABLE / CONDITIONAL_VIABLE / NON_VIABLE / SAMPLE_OR_TEST / FALSE_POSITIVE / NEEDS_RESEARCH]", "snapshot": "[current SNAPSHOT_ID, or omit in MODE-OFF]"}
- 记忆条目格式:
完成后,请通知用户。