mantis-reproduce

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Reproducer (/mantis-reproduce)

复现器(/mantis-reproduce)

System Goal

系统目标

Integration Test Engineer. Designs crash reproducers or inputs and executes them inside isolated sandbox environments to empirically verify bugs.
集成测试工程师。设计崩溃复现器或输入,并在隔离的沙箱环境中执行它们,以实证验证漏洞。

Command Definition

命令定义

  • Command:
    /mantis-reproduce [--reattack] [--finding_id=<uuid>] [--force] [--target_root=<path>] [--state_root=<path>] [--snapshot_root=<path>] [--snapshot_id=<SNAPSHOT_ID>] [--snapshot_pinned=<true|false>]
  • Description: Generates and runs crash reproducers to verify security flaws.
  • Parameters:
    • --reattack
      : When executing as part of patch verification to isolate re-attack outcomes.
    • --finding_id
      : The specific finding UUID to reproduce. Must be provided and is required when
      --reattack
      is specified.
    • --force
      : Override/bypass eligibility checks for targeted normal runs.
    • --target_root
      : Path to the root of the target codebase under test (defaults to
      .
      ). AUTHORITATIVE when supplied — overrides
      --snapshot_root
      (Block A step 1a); the sentinel check is skipped for this tree (e.g. a patched shadow during re-attack verification).
    • --state_root
      : Path to the root of the Mantis state directory containing
      workspace/
      (defaults to
      .
      ).
    • --snapshot_root
      : Root of the pinned immutable code snapshot for this pass. Consumed by Block A (Step 0) when
      --target_root
      is not supplied.
    • --snapshot_id
      : The SNAPSHOT_ID string of the pinned snapshot, consumed by Block A (sentinel) and Block B (snapshot match check) in Step 0.
    • --snapshot_pinned
      : When
      false
      (set by
      mantis-patch
      during re-attack on a patched shadow), the reproduce sub-agent MUST skip the snapshot sentinel/match check for this invocation — the
      --target_root
      tree is authoritative and sentinel-exempt (Block A step 1a).
  • 命令:
    /mantis-reproduce [--reattack] [--finding_id=<uuid>] [--force] [--target_root=<path>] [--state_root=<path>] [--snapshot_root=<path>] [--snapshot_id=<SNAPSHOT_ID>] [--snapshot_pinned=<true|false>]
  • 描述: 生成并运行崩溃复现器以验证安全漏洞。
  • 参数:
    • --reattack
      :在补丁验证过程中执行,用于隔离重攻击结果。
    • --finding_id
      :要复现的特定漏洞发现UUID。当指定
      --reattack
      必须提供此参数。
    • --force
      :针对常规运行,覆盖/绕过资格检查。
    • --target_root
      :被测目标代码库的根路径(默认为
      .
      )。当提供此参数时具有权威性——会覆盖
      --snapshot_root
      (Block A步骤1a);此代码树会跳过标记检查(例如重攻击验证期间的已修补副本)。
    • --state_root
      :包含
      workspace/
      的Mantis状态目录根路径(默认为
      .
      )。
    • --snapshot_root
      :本次运行的固定不可变代码快照根目录。当未提供
      --target_root
      时,由Block A(步骤0)使用。
    • --snapshot_id
      :固定快照的SNAPSHOT_ID字符串,由Block A(标记)和Block B(快照匹配检查)在步骤0中使用。
    • --snapshot_pinned
      :当设为
      false
      (由
      mantis-patch
      在对已修补副本进行重攻击时设置),复现子代理必须跳过本次调用的快照标记/匹配检查——
      --target_root
      树具有权威性且豁免标记检查(Block A步骤1a)。

Input/Output Contract

输入/输出约定

  • Reads:
    • state_root/workspace/findings/
      (viable/conditional findings).
    • target_root/
      (Repository source files to analyze trigger paths).
    • state_root/workspace/archive/.repro_attempts.json
      .
    • state_root/workspace/.mantis_state.json
      (to track current loop pass).
  • Writes:
    • PoC reproduction files (e.g.
      poc_[uuid].py
      or
      crash_[uuid].payload
      inside
      state_root/workspace/reproducers/
      ).
    • If run normally: updates findings in-place under
      state_root/workspace/findings/
      (sets
      "repro_status"
      ,
      "repro_file_path"
      ,
      "run_command"
      ,
      "repro_output"
      , and appends history). Updates status to
      "VALID"
      if provisionally valid.
    • If run with
      --reattack
      : updates findings in-place under
      state_root/workspace/findings/
      (sets
      "reattack_status"
      ,
      "reattack_file_path"
      ,
      "reattack_run_command"
      ,
      "reattack_output"
      ,
      "reattack_variants"
      , and appends history with stage
      "reattack"
      ). Does not modify
      "repro_*"
      fields or
      "status"
      . Exception: may atomically downgrade
      patch_status
      per INV-1 in Step 6 (never persist
      VERIFIED_SECURE
      alongside a non-
      failed_to_bypass
      reattack_status
      ).
    • Updates
      state_root/workspace/archive/.repro_attempts.json
      atomically.
    • Stamps
      "repro_snapshot_id"
      /
      "reattack_snapshot_id"
      on updated findings and stores
      .repro_attempts.json
      values as
      {count,last_snapshot}
      objects (bare integers still read correctly).
  • Preconditions:
    • Findings must exist in
      state_root/workspace/findings/
      .
    • Sandbox/container runtime environment must be available.
  • Idempotency Guarantee:
    • Updates findings in place. Uses
      state_root/workspace/archive/.repro_attempts.lock
      file locking and atomic temporary file swaps (
      os.replace
      on
      state_root/workspace/archive/.repro_attempts.json.tmp
      ) to guarantee concurrency safety and retry stability.
    • Snapshot-aware: regenerates the PoC when the finding's snapshot no longer matches; refuses to emit a negative verdict without reached-sink evidence. Re-attack verdicts on a snapshot mismatch are governed by the C5 unpatched-baseline re-run (Step 6), which supersedes the legacy blanket refusal — a
      failed_to_bypass
      verdict is only written after C5 has confirmed the unpatched baseline still triggers on the current snapshot.
  • 读取:
    • state_root/workspace/findings/
      (可行/有条件的漏洞发现结果)。
    • target_root/
      (用于分析触发路径的仓库源文件)。
    • state_root/workspace/archive/.repro_attempts.json
    • state_root/workspace/.mantis_state.json
      (用于跟踪当前循环运行次数)。
  • 写入:
    • PoC复现文件(例如
      state_root/workspace/reproducers/
      目录下的
      poc_[uuid].py
      crash_[uuid].payload
      )。
    • 常规运行时:在
      state_root/workspace/findings/
      中就地更新漏洞发现结果(设置
      "repro_status"
      "repro_file_path"
      "run_command"
      "repro_output"
      ,并追加历史记录)。如果临时验证有效,则将状态更新为
      "VALID"
    • 使用
      --reattack
      运行时:在
      state_root/workspace/findings/
      中就地更新漏洞发现结果(设置
      "reattack_status"
      "reattack_file_path"
      "reattack_run_command"
      "reattack_output"
      "reattack_variants"
      ,并追加阶段为
      "reattack"
      的历史记录)。不会修改
      "repro_*"
      字段或
      "status"
      例外情况: 根据步骤6中的INV-1,可能会原子性降级
      patch_status
      (永远不会在
      reattack_status
      failed_to_bypass
      的情况下保留
      VERIFIED_SECURE
      )。
    • 原子性更新
      state_root/workspace/archive/.repro_attempts.json
    • 在更新的漏洞发现结果上标记
      "repro_snapshot_id"
      /
      "reattack_snapshot_id"
      ,并将
      .repro_attempts.json
      的值存储为
      {count,last_snapshot}
      对象(仍可正确读取纯整数值)。
  • 前置条件:
    • state_root/workspace/findings/
      中必须存在漏洞发现结果。
    • 必须具备沙箱/容器运行时环境。
  • 幂等性保证:
    • 就地更新漏洞发现结果。使用
      state_root/workspace/archive/.repro_attempts.lock
      文件锁和原子性临时文件替换(对
      state_root/workspace/archive/.repro_attempts.json.tmp
      执行
      os.replace
      ),以保证并发安全性和重试稳定性。
    • 快照感知:当漏洞发现结果的快照不再匹配时,重新生成PoC;在没有到达漏洞点证据的情况下,拒绝给出否定结论。快照不匹配时的重攻击结论由C5未修补基线重新运行(步骤6)管理,这取代了传统的全面拒绝规则——只有在C5确认未修补基线在当前快照上仍能触发漏洞后,才会写入
      failed_to_bypass
      结论。

Instructions

操作说明

Step 0: Locator Resolution + Snapshot Match (run first)

步骤0:定位器解析 + 快照匹配(首先运行)

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.
[!NOTE] CURRENT-PASS CHECK (defensive; the binding guarantee is on the harness per
mantis-pipeline-adapter
Scenario 2):
if
active_snapshot
is present AND
active_snapshot.pass != state.pass_number
, treat the snapshot as STALE for this pass — STOP "stale active_snapshot: pass mismatch" or degrade as HALT (
snapshot_pinned
effectively false: no authoritative verdicts, Block B NOT_MATCHED, reproduce
not_attempted
). This catches a custom harness that preserved
active_snapshot
across the Stage 15 pass increment without re-pinning. The reference meta-agent re-pins every pass, so this check never fires there. Block B itself cannot detect this (it is
snapshot_id
-only, not
pass
-aware).
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.)
Notes: When invoked by the patcher with
--target_root=<shadow>
(a patched copy), Block A step 1a makes that shadow the authoritative CODE_ROOT and SKIPS the sentinel check (the shadow is deliberately mutated). Otherwise CODE_ROOT is the pinned snapshot and the sentinel MUST match. Stamp
repro_snapshot_id
(normal run) or
reattack_snapshot_id
(
--reattack
) = the current SNAPSHOT_ID (from
--snapshot_id
or state
active_snapshot.snapshot_id
) on every finding you update.
Write a Proof-of-Concept Reproduction Script (Repro) or raw input payload file that reproduces a confirmed security flaw.
Execute the reproduction stage under these constraints:
  1. Load Viable Findings:
    • If
      --finding_id
      is supplied:
      • Load only that finding's file (
        state_root/workspace/findings/<uuid>.json
        ). Exit if it does not exist.
      • If
        --reattack
        is specified: Enforce the expected patch workflow state for the loaded finding:
        • The finding's
          "status"
          must be
          "VALID"
          or
          "PROVISIONALLY_VALID"
          .
        • The finding's
          "repro_status"
          must be
          "reproduced"
          .
        • The finding's
          "patch_status"
          must NOT be
          "MITIGATION_PROPOSED"
          . (
          VERIFIED_SECURE
          IS allowed: C5 below atomically downgrades it when the re-attack outcome is not
          failed_to_bypass
          .)
        • Exit with an error if these conditions are not met, explaining the invalid state.
      • If
        --reattack
        is NOT specified (Targeted Normal Run):
        • If
          --force
          is NOT specified, enforce standard eligibility filters:
          • The finding's
            "status"
            must be
            "VALID"
            or
            "PROVISIONALLY_VALID"
            .
          • The finding's
            "production_viability"
            must be
            "VIABLE"
            ,
            "SAMPLE_OR_TEST"
            , or
            "CONDITIONAL_VIABLE"
            .
          • Exit with an error if these conditions are not met, explaining the invalid state.
        • If
          --force
          is specified, bypass these eligibility checks.
    • If
      --finding_id
      is not supplied:
      • Constraint: Exit if
        --reattack
        is specified (it requires
        --finding_id
        ).
      • Read the JSON files in the
        state_root/workspace/findings/
        directory.
      • Strict Eligibility Filter (Normal Runs): Include only findings where:
        • "status"
          is
          "VALID"
          or
          "PROVISIONALLY_VALID"
          .
        • "production_viability"
          is
          "VIABLE"
          ,
          "SAMPLE_OR_TEST"
          , or
          "CONDITIONAL_VIABLE"
          (or skip this viability filter if not checking viability, but always check status).
      • If no applicable findings exist, notify the user and exit.
    Tier 0 — Structural Reachability Pre-Check (Advisory Queue Sorting): If a structural code index (
    mantis-structural-index
    ) is available, you MAY query
    query_structural_index.py
    (
    find_callers
    ) before authoring code to check whether an AST call path exists from a public entrypoint to the vulnerable sink. Use this query to prioritize candidate execution order (process findings with verified AST reachability first).
    • CRITICAL HINT-ONLY GUARDRAIL: AST reachability is a ranking HINT ONLY. Call graphs miss macros, function pointers, dynamic dispatch, and interface tables. An absent call path MUST NEVER reject a finding, skip reproduction, or set
      failed_to_reproduce
      .
    Snapshot drift check: For each loaded finding, if it already has a
    repro_snapshot_id
    and Block B (Step 0) returns NOT_MATCHED, treat any stored PoC/offsets as STALE: regenerate the reproducer from scratch against the current CODE_ROOT (do not reuse old line numbers/addresses). If Block B is MATCHED you may reuse an existing PoC.
  2. Strict Host Isolation Constraint:
    • Host command execution is strictly prohibited. Do not run commands directly on your parent host terminal using terminal/shell execution tools.
    • All reproducer executions must run isolated. Use the containerization or sandbox execution tools provided by your environment. For memory-safety PoCs, restrict network access and file system writes as much as possible. For logic/auth functional tests, you may enable local network services as needed, but never expose the environment to the external internet.
  3. Writing and Launching the Reproducer: Write a self-contained test script (e.g.,
    poc_[uuid].py
    or a C reproducer file in the same directory) or write a raw crash input data payload (e.g.,
    crash_[uuid].payload
    ) that triggers the target bug. All generated PoC/re-attack scripts and payloads MUST be written inside the
    state_root/workspace/reproducers/
    directory (never in the
    target_root
    directory).
    You must ensure the parent directory
    state_root/workspace/reproducers/
    exists (e.g. using
    mkdir -p
    ) before writing any files. Analyze the code path and constraints carefully. If your initial reproduction attempt fails, evaluate if the finding details (such as input paths, parameters, or assumptions) are slightly incorrect based on your observations, and adjust the finding details dynamically to attempt a fix. If you cannot find a triggerable path after trying multiple approaches and adjustments, abandon the attempt. Do NOT directly mark it as
    failed_to_reproduce
    — route the abandon decision through the Step-5 Block F (Reached-Sink Evidence) gate: if the harness provably reached the vulnerable entrypoint but the bug did not fire, classify as
    failed_to_reproduce
    ; if evidence is absent (setup/build failure, exit 127, "No such file", or the sink was never reached), classify as
    not_attempted
    (retry-eligible). A raw negative from a setup/build failure burns the retry cap and silently drops a real bug.
    To run your script or payload, use the execution or containerization tools available in your environment to execute the code safely. Select the most appropriate runtime image and flags for the target. All compilation and test execution commands MUST be run in a PRIVATE BUILD SHADOW, never with Cwd=CODE_ROOT (the snapshot is read-only — Block A step 4). Before compiling, create
    BUILD_ROOT=$(mktemp -d)
    and copy CODE_ROOT into it (e.g.
    cp -a CODE_ROOT/. BUILD_ROOT/
    ); run all compilation/test commands with Cwd=BUILD_ROOT; delete BUILD_ROOT on teardown. Keep the generated PoC file itself under
    state_root/workspace/reproducers/
    (STATE-RELATIVE) and store its ABSOLUTE path in
    "run_command"
    /
    "reattack_run_command"
    .
    Sanitizer compilation (C/C++ targets): When the bug class is memory-safety or undefined-behavior, compile with
    -fsanitize=address,undefined
    (ASan + UBSan) at a minimum. For data races, add
    -fsanitize=thread
    (TSan) — TSan is also mutually exclusive with ASan, so use a separate build. Use
    -fno-omit-frame-pointer
    for usable stack traces. These flags surface bugs that would otherwise exit 0 silently (UBSan defaults to recover-mode). MSan caveat: MemorySanitizer (
    -fsanitize=memory
    ) detects uninitialized-memory reads, but it requires the ENTIRE dependency chain (including libc and the C++ runtime) to be MSan-instrumented — on an arbitrary target that is usually not the case, so a naive
    -fsanitize=memory
    build yields bogus
    WARNING: MemorySanitizer
    traces. MSan is also mutually exclusive with ASan in one build (use a separate build, not an additive flag). If a fully instrumented MSan environment cannot be guaranteed, do NOT add
    -fsanitize=memory
    ; fall back to ASan+UBSan rather than trusting a possibly-bogus MSan trace. Recognizing MSan output as evidence (Step 5) is still correct when a legitimate MSan instrumented build is available. Sanitizer consistency guardrail: the SAME sanitizer flags MUST be used for the baseline, attack, and re-attack runs — a different sanitizer can mask the bug and produce a false negative (INV-2) or false
    VERIFIED_SECURE
    (INV-1). See Block G.
    {TARGET_ROOT} token substitution (numbered step):
    1. When writing
      run_command
      or
      reattack_run_command
      , use the literal token
      {TARGET_ROOT}
      for any path that references the target tree.
    2. At run time, reproduce substitutes
      {TARGET_ROOT}
      with the actual root:
      • On first execution:
        CODE_ROOT
        (the snapshot or
        --target_root
        ).
      • On re-execution (re-attack or retry): the current
        CODE_ROOT
        /
        --target_root
        /
        active_snapshot.root
        .
    3. This ensures the stored command resolves correctly after snapshot GC — never bake an absolute
      .mantis_snapshots/pass_<N>
      path into the stored command.
    Execute your reproduction using the appropriate environment: If the target is firmware, you may write a script to boot it via
    qemu
    ,
    unicorn
    , or Firmadyne. If it's a binary, you may use dynamic instrumentation or standard execution. Use your best judgment to construct a working harness for the artifact.
    • Parallel Trajectory Search vs. Tiered Iterative Reproduction:
      • Parallel Trajectory Search (Breadth-First): When subagents are available, deploy concurrent workers taking diverse logical approaches to reproduce the bug. If any trajectory succeeds, immediately adopt its payload and discard the others to escape potential "give up" loops and prune compute costs.
      • Tiered Iterative Reproduction (Depth-First Payload Refinement): Each trajectory worker (or a single agent) uses a tiered escalation ladder (Tier 1 -> Tier 2 -> Tier 3) to refine its trigger payload incrementally rather than attempting a single-shot end-to-end launch.
    • Tiered Iterative Execution Ladder:
      • Tier 1 (Micro-Harness / Sink Logic Validation): Construct a lightweight test calling the vulnerable function/module directly to verify that the core bug hypothesis is sound in isolation.
      • Tier 2 (Subsystem / Interface Validation): Pass the payload through input serialization, parsers, routing, and auth wrappers to verify the input survives intermediate processing without sanitization or truncation.
      • Tier 3 (Full Sandboxed Service / E2E Validation): Execute the self-contained PoC against the target service via public APIs inside the isolated sandbox (Docker, QEMU, VM). Yields the authoritative
        reproduced
        verdict per Block F.
    • CRITICAL STEP-4 TIER-1 HARD GATE (Fail-Closed):
      • Tiers 1 and 2 are internal stepping stones only. You MUST NEVER record
        repro_status = "reproduced"
        or
        "statically_confirmed"
        based on a Tier-1 or Tier-2 execution.
      • If a crash can ONLY be achieved by compiling a direct-call harness that feeds a private/static function or bypasses the public API (Step 4), and the payload cannot be escalated to trigger through Tier 3 (the public API / sandboxed service), you MUST TERMINATE AND RECORD
        repro_status = "failed_to_reproduce"
        with details citing
        "Internal Invariant Protection"
        .
    • Attempt Cap Accounting & Local Retries:
      • Sub-Tier-3 Stepping-Stone Sub-Budget: Internal Tier-1 and Tier-2 trial runs are bounded local execution steps (max 3 trial executions per conversation) and DO NOT increment the absolute per-finding attempt counter in
        state_root/workspace/archive/.repro_attempts.json
        .
      • Absolute Attempt Cap Counting: Only Tier-3 full sandboxed service executions (or full end-to-end reproducer runs) increment the absolute attempt counter toward the hard ceiling of 6 (Section 6).
      • Intra-Conversation Retries: When a tier fails, inspect logs, adjust payload parameters, fix harness setup, and retry up to 2-3 times within the active conversation before reporting back to the orchestrator.
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.
[!NOTE] 当前运行检查(防御性;
mantis-pipeline-adapter
场景2中的绑定保证):
如果存在
active_snapshot
active_snapshot.pass != state.pass_number
,则将该快照视为当前运行的过期快照——停止并提示"stale active_snapshot: pass mismatch",或降级为HALT(
snapshot_pinned
等效为false:无权威结论,Block B为NOT_MATCHED,复现状态为
not_attempted
)。这可以捕获自定义工具在阶段15运行次数增加后仍保留
active_snapshot
但未重新固定的情况。参考元代理每次运行都会重新固定快照,因此此检查在参考环境中永远不会触发。Block B本身无法检测到这一点(它仅感知
snapshot_id
,不感知
pass
)。
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.)
注意:当补丁工具使用
--target_root=<shadow>
(已修补副本)调用时,Block A步骤1a会将该副本设为权威CODE_ROOT并跳过标记检查(该副本是故意修改的)。否则CODE_ROOT是固定快照,且标记必须匹配。在每个您更新的漏洞发现结果上标记
repro_snapshot_id
(常规运行)或
reattack_snapshot_id
--reattack
)= 当前SNAPSHOT_ID(来自
--snapshot_id
或状态中的
active_snapshot.snapshot_id
)。
编写用于复现已确认安全漏洞的概念验证(Proof-of-Concept,PoC)复现脚本或原始输入载荷文件。
在以下约束下执行复现阶段:
  1. 加载可行的漏洞发现结果:
    • 如果提供了
      --finding_id
      • 仅加载该漏洞发现结果的文件(
        state_root/workspace/findings/<uuid>.json
        )。如果文件不存在则退出。
      • 如果指定了
        --reattack
        :对加载的漏洞发现结果强制执行预期的补丁工作流状态
        • 漏洞发现结果的
          "status"
          必须为
          "VALID"
          "PROVISIONALLY_VALID"
        • 漏洞发现结果的
          "repro_status"
          必须为
          "reproduced"
        • 漏洞发现结果的
          "patch_status"
          不得为
          "MITIGATION_PROPOSED"
          。(允许
          VERIFIED_SECURE
          :下面的C5会在重攻击结果非
          failed_to_bypass
          时原子性降级它。)
        • 如果这些条件未满足,则退出并报错,说明无效状态。
      • 如果未指定
        --reattack
        (定向常规运行):
        • 如果未指定
          --force
          ,强制执行标准资格筛选:
          • 漏洞发现结果的
            "status"
            必须为
            "VALID"
            "PROVISIONALLY_VALID"
          • 漏洞发现结果的
            "production_viability"
            必须为
            "VIABLE"
            "SAMPLE_OR_TEST"
            "CONDITIONAL_VIABLE"
          • 如果这些条件未满足,则退出并报错,说明无效状态。
        • 如果指定了
          --force
          ,则绕过这些资格检查。
    • 如果未提供
      --finding_id
      • 约束: 如果指定了
        --reattack
        则退出(它需要
        --finding_id
        )。
      • 读取
        state_root/workspace/findings/
        目录下的JSON文件。
      • 常规运行严格资格筛选: 仅包含以下漏洞发现结果:
        • "status"
          "VALID"
          "PROVISIONALLY_VALID"
        • "production_viability"
          "VIABLE"
          "SAMPLE_OR_TEST"
          "CONDITIONAL_VIABLE"
          (如果不检查可行性,则跳过此筛选,但始终检查状态)。
      • 如果没有适用的漏洞发现结果,则通知用户并退出。
    第0层——结构可达性预检查(建议队列排序): 如果存在结构化代码索引(
    mantis-structural-index
    ),您可以在编写代码前查询
    query_structural_index.py
    find_callers
    ),以检查是否存在从公共入口点到漏洞点的AST调用路径。使用此查询来优先处理候选执行顺序(先处理已验证AST可达性的漏洞发现结果)。
    • 关键提示性护栏: AST可达性仅作为排名提示。调用图会遗漏宏、函数指针、动态调度和接口表。即使不存在调用路径,也绝对不能拒绝漏洞发现结果、跳过复现或设置
      failed_to_reproduce
    快照漂移检查: 对于每个加载的漏洞发现结果,如果它已有
    repro_snapshot_id
    且Block B(步骤0)返回NOT_MATCHED,则将任何存储的PoC/偏移视为过期:针对当前CODE_ROOT从头重新生成复现器(不要重用旧的行号/地址)。如果Block B返回MATCHED,则可以重用现有PoC。
  2. 严格主机隔离约束:
    • 严格禁止在主机上执行命令。不要使用终端/ shell执行工具直接在父主机终端运行命令。
    • 所有复现器执行必须在隔离环境中运行。使用环境提供的容器化或沙箱执行工具。对于内存安全PoC,尽可能限制网络访问和文件系统写入。对于逻辑/授权功能测试,您可以根据需要启用本地网络服务,但绝不能将环境暴露到外部互联网。
  3. 编写并启动复现器: 编写自包含的测试脚本(例如同一目录下的
    poc_[uuid].py
    或C复现文件),或编写原始崩溃输入数据载荷(例如
    crash_[uuid].payload
    )来触发目标漏洞。所有生成的PoC/重攻击脚本和载荷必须写入
    state_root/workspace/reproducers/
    目录(绝不能写入
    target_root
    目录)。
    在写入任何文件之前,您必须确保父目录
    state_root/workspace/reproducers/
    存在(例如使用
    mkdir -p
    )。仔细分析代码路径和约束。如果初始复现尝试失败,请根据观察结果评估漏洞发现结果的细节(例如输入路径、参数或假设)是否略有不正确,并动态调整漏洞发现结果的细节以尝试修复。如果尝试多种方法和调整后仍无法找到可触发的路径,则放弃尝试。请勿直接将其标记为
    failed_to_reproduce
    ——通过步骤5的Block F(到达漏洞点证据)门来处理放弃决策:如果工具已证明到达漏洞入口点但漏洞未触发,则分类为
    failed_to_reproduce
    ;如果没有证据(设置/构建失败、退出码127、"No such file"或从未到达漏洞点),则分类为
    not_attempted
    (可重试)。设置/构建失败导致的直接否定结果会耗尽重试上限,可能会遗漏真实漏洞。
    要运行您的脚本或载荷,请使用环境中可用的执行或容器化工具安全地执行代码。为目标选择最合适的运行时镜像和标志。所有编译和测试执行命令必须在私有构建副本(PRIVATE BUILD SHADOW)中运行,绝不能以Cwd=CODE_ROOT运行(快照是只读的——Block A步骤4)。 编译前,创建
    BUILD_ROOT=$(mktemp -d)
    并将CODE_ROOT复制到其中(例如
    cp -a CODE_ROOT/. BUILD_ROOT/
    );以Cwd=BUILD_ROOT运行所有编译/测试命令;在清理时删除BUILD_ROOT。将生成的PoC文件本身保存在
    state_root/workspace/reproducers/
    (状态相对路径)下,并将其绝对路径存储在
    "run_command"
    /
    "reattack_run_command"
    中。
    Sanitizer编译(C/C++目标): 当漏洞类型为内存安全或未定义行为时,至少使用
    -fsanitize=address,undefined
    (ASan + UBSan)进行编译。对于数据竞争,添加
    -fsanitize=thread
    (TSan)——TSan也与ASan互斥,因此需使用单独的构建。使用
    -fno-omit-frame-pointer
    以获得可用的堆栈跟踪。这些标志会暴露否则会静默退出码0的漏洞(UBSan默认使用恢复模式)。MSan注意事项: MemorySanitizer(
    -fsanitize=memory
    )检测未初始化内存读取,但它要求整个依赖链(包括libc和C++运行时)都经过MSan检测——对于任意目标,通常无法满足此条件,因此简单的
    -fsanitize=memory
    构建会产生虚假的
    WARNING: MemorySanitizer
    跟踪。MSan也与ASan在同一构建中互斥(使用单独的构建,而非添加标志)。如果无法保证完全检测的MSan环境,则不要添加
    -fsanitize=memory
    ;退而使用ASan+UBSan,而不要信任可能虚假的MSan跟踪。当存在合法的MSan检测构建时,将MSan输出视为证据(步骤5)仍然是正确的。Sanitizer一致性护栏: 基线运行、攻击运行和重攻击运行必须使用相同的Sanitizer标志——不同的Sanitizer可能会掩盖漏洞并产生假阴性(INV-2)或假
    VERIFIED_SECURE
    (INV-1)。请参见Block G。
    {TARGET_ROOT}令牌替换(编号步骤):
    1. 编写
      run_command
      reattack_run_command
      时,对任何引用目标树的路径使用字面令牌
      {TARGET_ROOT}
    2. 在运行时,复现器会将
      {TARGET_ROOT}
      替换为实际根路径:
      • 首次执行时:
        CODE_ROOT
        (快照或
        --target_root
        )。
      • 重新执行时(重攻击或重试):当前
        CODE_ROOT
        /
        --target_root
        /
        active_snapshot.root
    3. 这确保存储的命令在快照垃圾回收后仍能正确解析——永远不要将绝对路径
      .mantis_snapshots/pass_<N>
      硬编码到存储的命令中。
    使用适当的环境执行复现: 如果目标是固件,您可以编写脚本通过
    qemu
    unicorn
    或Firmadyne启动它。如果是二进制文件,您可以使用动态插桩或标准执行。请根据最佳判断为工件构建可用的工具。
    • 并行轨迹搜索 vs. 分层迭代复现:
      • 并行轨迹搜索(广度优先): 如果有子代理可用,部署并发工作者采用不同的逻辑方法来复现漏洞。如果任何轨迹成功,立即采用其载荷并丢弃其他轨迹,以避免潜在的"放弃"循环并减少计算成本。
      • 分层迭代复现(深度优先载荷优化): 每个轨迹工作者(或单个代理)使用分层升级阶梯(第1层→第2层→第3层)来逐步优化其触发载荷,而非尝试一次性端到端启动。
    • 分层迭代执行阶梯:
      • 第1层(微工具/漏洞点逻辑验证): 构建轻量级测试直接调用漏洞函数/模块,以验证核心漏洞假设在隔离环境中是否成立。
      • 第2层(子系统/接口验证): 通过输入序列化、解析器、路由和授权包装器传递载荷,以验证输入在中间处理过程中未被 sanitize 或截断。
      • 第3层(完整沙箱服务/端到端验证): 在隔离沙箱(Docker、QEMU、VM)内通过公共API针对目标服务执行自包含PoC。根据Block F得出权威的
        reproduced
        结论。
    • 关键步骤4第1层硬门(故障关闭):
      • 第1层和第2层仅作为内部垫脚石。您绝不能基于第1层或第2层的执行记录
        repro_status = "reproduced"
        "statically_confirmed"
      • 如果只能通过编译直接调用工具(绕过公共API)来触发崩溃,而无法将载荷升级到第3层(公共API/沙箱服务)触发,则您必须终止并记录
        repro_status = "failed_to_reproduce"
        ,并注明
        "Internal Invariant Protection"
    • 尝试上限统计与本地重试:
      • 第3层以下垫脚石子预算: 内部第1层和第2层试运行是有界的本地执行步骤(每次对话最多3次试运行),并且不会增加
        state_root/workspace/archive/.repro_attempts.json
        中每个漏洞发现结果的绝对尝试计数器。
      • 绝对尝试上限统计: 只有第3层完整沙箱服务执行(或完整端到端复现器运行)才会增加绝对尝试计数器,直至硬上限6(第6节)。
      • 对话内重试: 当某一层失败时,检查日志、调整载荷参数、修复工具设置,并在当前对话内重试2-3次,然后向编排器报告。

Step 3a: Variant Hunting (re-attack only, MANDATORY)

步骤3a:变体搜索(仅重攻击时需要,强制要求)

When invoked with
--reattack
, you MUST author and execute N ≥ 3 boundary-mutated variant inputs in addition to re-running the original PoC. The schema (
schema.json
) literally calls this the "variant-hunting re-attack" — merely re-running the original PoC is insufficient. Over-narrow patches that guard the exact PoC bytes are the dominant auto-repair failure mode; variant hunting is the zero-infra-cost defense against them.
Legacy findings: Findings with absent
reattack_variants
(created before this rule existed) are re-verified under the ≥3 variant requirement on their first
--reattack
pass. This is intentional — legacy
VERIFIED_SECURE
verdicts are upgraded to the stricter gate — but expect one-time churn across archived findings on the first pass that runs variant hunting.
What to generate (bug-class-aware):
  • Memory-safety bugs (buffer overflow, OOB read/write, UAF, integer overflow): Author at least 3 of:
    • Off-by-one:
      len = bound
      ,
      len = bound + 1
      ,
      len = bound - 1
      .
    • Size mutations:
      len ± 1
      ,
      len = 0
      ,
      len = SIZE_MAX
      , sign flips on signed lengths.
    • Alternate paths to the same sink: If the vulnerable sink is reached via multiple call sites, author a variant reaching it through a different path (e.g., different API endpoint, file format variant, or protocol command).
    • Type confusion / width mismatch: Exploit a different type path to the same sink.
  • Non-memory-safety bugs (logic, auth, injection, SSRF, path traversal): Hunt for actual variants of the same class:
    • Alternate endpoints/parameters: Try
      /api/v2/echo
      when PoC targets
      /api/v1/echo
      , or alternate parameter names.
    • Equivalent payloads:
      ..%2fetc%2fpasswd
      ,
      ..\\..\\
      , URL-encoding, double encoding, unicode normalization variants.
    • Auth boundary variants: Different roles, empty/null tokens, alternate privilege-escalation paths.
    • Injection variants:
      '; EXEC--
      ,
       UNION SELECT
      , blind variants, alternate injection points.
  • Parallel variant generation (if subagents available): You SHOULD spawn subagents to author and test variants in parallel. Each subagent gets one mutation strategy, writes its variant PoC, and reports whether it triggered. Aggregate all results before setting
    reattack_status
    . If subagents are unavailable, do them sequentially.
Execution: Write each variant as a separate script in
state_root/workspace/reproducers/
(e.g.,
reattack_variant_[uuid]_[N].py
). Execute each against the patched shadow (
--target_root
) using the same isolation constraints as Step 3. Record each variant in the
reattack_variants
array using EXACTLY the schema keys
{"description": "...", "triggered": true/false}
(Step 6).
Verdict rule:
reattack_status = "failed_to_bypass"
requires a non-empty
reattack_variants
array containing ≥ 3 valid variant inputs that ALL failed to trigger the bug on the patched shadow. An empty or short set makes "all variants failed" vacuously true — this is FORBIDDEN: if fewer than 3 meaningful variants can be constructed after genuine effort, cap at
VERIFICATION_INCOMPLETE
(history note
insufficient_variants
), NEVER
failed_to_bypass
. The
[]
case may ONLY coexist with a non-
failed_to_bypass
status (e.g., C5 baseline failure that halted before variant hunting).
Variant validity guardrail: A variant counts as a bypass (
triggered = true
causing
bypassed_patch
) ONLY if it satisfies BOTH:
  1. Same vulnerability class: The variant reproduces the original bug class — same sink function / sanitizer signature / crash type. A junk mutant (e.g.,
    len=SIZE_MAX
    causing an unrelated OOM, an alternate endpoint 404-ing then erroring, or a completely different crash) does NOT count as a bypass. Discard it (set
    triggered = false
    with a description noting it was invalid) and continue. For non-memory bugs (logic, auth, injection), compare the same sink function or behavior (e.g., same unauthorized action succeeds, same injection executes, reaches the same sink function) — NOT a ±line window against a pre-patch line number (patches shift lines, and non-memory bugs often have no precise sink line). If you cannot positively confirm a triggering variant is a DIFFERENT bug, count it as a bypass (fail-closed: prefer a false VERIFICATION_FAILED over a false VERIFIED_SECURE).
  2. Valid input per Step 4: The variant must be a valid exercise of the public API or internal invariants — it must not rely on artificial harness tricks (e.g., private-function direct calls with custom-allocated buffers) that bypass the library's execution invariants.
Ideally, confirm each triggering variant still triggers on the unpatched shadow (same baseline the original PoC ran against) to prove it exercises the original bug rather than an artifact. If the unpatched shadow is unavailable (e.g., snapshot mismatch), require the same-sink evidence (same sanitizer frame, same crash address, same logic failure) as corroboration.
If ANY valid variant triggers the bug, set
reattack_status = "bypassed_patch"
and apply INV-1 (downgrade
VERIFIED_SECURE
VERIFICATION_FAILED
).
  • Reproduction Status Classification:
    • reproduced
      : The PoC successfully triggered the vulnerability.
    • failed_to_reproduce
      : The PoC was executed but did not trigger the vulnerability.
    • statically_confirmed
      : Reproduction was impossible due to environmental constraints (e.g., missing hardware emulators, unavailable external services) but the flaw is statically obvious (e.g., hardcoded credentials). This is strongly discouraged and should only be used as a last resort.
    • not_attempted
      : The reproduction stage was skipped entirely (e.g., due to infrastructure setup failure, timeouts, or explicit skip configuration).
  1. Strict Public-API & Internal Invariant Constraints:
    • Your crash reproducer should interact with the codebase through public-facing APIs wherever possible, or strictly respect the library's global execution invariants (such as allocator padding) to avoid generating artificial, non-viable crashes.
    • Do not declare a finding as "reproduced" if the crash can only be achieved by compiling a direct-call harness that feeds a private/static function a custom-allocated buffer (e.g.,
      malloc(15)
      ) that bypasses the library's guaranteed allocator wrappers (e.g.,
      png_malloc(rowbytes + 48)
      ).
    • If a crash cannot be triggered through the public API or with standard allocation padding, classify the finding as
      "failed_to_reproduce"
      due to "Internal Invariant Protection."
  2. Functional & Crash-Aware Validation: Analyze the output such as stdout, stderr, and exit codes to classify reproduction success depending on the bug class:
    Before classifying ANY negative outcome (
    failed_to_reproduce
    , or in
    --reattack
    mode
    failed_to_bypass
    ), apply this gate:
    REACHED-SINK EVIDENCE GATE (mechanical):
    Each reproducer produces REACHED-SINK EVIDENCE via ONE channel, recorded in repro_hints:
       (a) script/source harness -> write the exact bytes MANTIS_REACHED_ENTRYPOINT to a
           sidecar file $SENTINEL_FILE and flush+fsync (or unbuffered write) BEFORE
           invoking the sink. (A file survives a crash that truncates buffered stdout.)
       (b) binary / firmware / raw-payload -> reached-sink evidence is a captured
           crash backtrace or sanitizer frame (ASan/UBSan/MSan/TSan) that
           explicitly names the target sink function (target-produced tracing). A
           marker written by a wrapper you author BEFORE invoking the target is
           SETUP EVIDENCE ONLY: it proves "launch attempted," not "sink reached,"
           and does NOT qualify as reached-sink evidence. If no in-path marker
           (channel a) and no target-produced backtrace/sanitizer trace
           (channel b) is achievable, the sink is unreached.
     EVIDENCE PRESENT (reached-sink) = (channel a) sidecar file contains
       MANTIS_REACHED_ENTRYPOINT written in-path, OR (channel b) target-produced
       backtrace/sanitizer output names the sink. A wrapper pre-launch marker alone is
       NOT evidence present.
    EVIDENCE ABSENT includes: any compiler/build nonzero exit; exit 127 (command not
      found); exit 2 with a "No such file" message.
    DECISION GATE (gate the DECISION, not specific verdict strings):
      - Record repro_status = reproduced OR statically_confirmed ONLY if EVIDENCE is
        PRESENT. If ABSENT -> repro_status = not_attempted (retry-eligible), STOP.
      - In patch verification, EVIDENCE is required on the UNPATCHED baseline (Block G),
        NOT on the post-patch attack run (a correct patch legitimately stops the input
        before the sink).
      - If NO evidence channel is achievable for this target, downgrade to
        not_attempted / VERIFICATION_INCOMPLETE. NEVER synthesize the marker.
    Concretely: if the run produced NO reached-sink evidence (build/setup error, exit 127, "No such file", or the sink was never reached), record
    repro_status = not_attempted
    (retry-eligible) — NEVER
    failed_to_reproduce
    ; and in
    --reattack
    mode leave
    reattack_status
    UNSET with a history note "setup_failed" — NEVER
    failed_to_bypass
    . Only classify a negative when the harness provably reached the vulnerable entrypoint and the bug did not fire.
    HALT ceiling (3-state rule): If
    active_snapshot
    is present in state but
    snapshot_pinned
    is
    false
    (HALT mode — the tree raced or could not be pinned), you MUST NOT record
    failed_to_reproduce
    or
    failed_to_bypass
    at all. In HALT, the code may have drifted and a negative reproduction result cannot be trusted as authoritative. Instead, record
    repro_status = not_attempted
    (retry-eligible) and, in
    --reattack
    mode, leave
    reattack_status
    UNSET with a history note "HALT mode: snapshot unpinned, negative result suppressed". This mirrors the authoritative-verdict prohibition that applies to all stages in HALT. (In MODE-OFF — no
    active_snapshot
    — classify negatives normally as today.)
    • Logic & Authorization Bugs: A successful reproducer is a functional unit test or script that explicitly demonstrates the logic failure (e.g., an unauthorized request returns
      200 OK
      , or a test script successfully bypasses validation and exits with
      0
      ).
    • Memory Safety & Binary Crashes: If the sandbox execution produces a crash signal or sanitizer trace in stdout/stderr, mark the reproduction as
      "reproduced"
      . Scan stdout/stderr for sanitizer signatures regardless of exit code — UBSan defaults to recover-mode (exit 0), so an exit-0 run can still contain a valid UBSan trace proving the bug fired. Check for:
      • AddressSanitizer (ASan) error outputs (e.g.
        ERROR: AddressSanitizer
        ).
      • UndefinedBehaviorSanitizer (UBSan) runtime reports (e.g.
        runtime error:
        ,
        SUMMARY: UndefinedBehaviorSanitizer
        ).
      • MemorySanitizer (MSan) error outputs (e.g.
        WARNING: MemorySanitizer
        ). MSan evidence is valid ONLY if
        repro_hints
        records that a fully-instrumented MSan build was available
        (Step 3 caveat). A naive
        -fsanitize=memory
        build without full instrumentation produces bogus traces — do NOT classify these as
        "reproduced"
        .
      • ThreadSanitizer (TSan) race reports (e.g.
        WARNING: ThreadSanitizer
        ).
      • Segmentation faults (SIGSEGV, exit code
        139
        ).
      • Abort signals (SIGABRT, exit code
        134
        ).
      • Crash or core dumps.
  3. Token-Optimized File Updates: To minimize LLM output tokens, do not re-emit or manually rewrite the entire JSON object in your output. Instead, use in-place editing tools (like a short script in your preferred language, or
    jq
    ) to programmatically append the new fields to the existing
    state_root/workspace/findings/<id>.json
    file.
    Additionally, you must Update the Reproduction Attempt Cache to help the planner track attempts efficiently:
    • Maintain a JSON cache file at
      state_root/workspace/archive/.repro_attempts.json
      . Ensure the parent directory
      state_root/workspace/archive/
      exists (e.g.,
      mkdir -p state_root/workspace/archive/
      ) before creating, reading, or locking the cache file.
    • Key the cache by a stable identifier that persists across loop runs even if UUIDs are regenerated. If the finding has a
      signature
      field, use it directly as the cache key (it is already a deterministic content-identity hash). If
      signature
      is absent, fall back to a computed stable key using the finding's normalized title and its primary file path:
      stable_key = normalized_title + "@" + primary_file_path
      .
      • Compute
        normalized_title
        by converting the title to lowercase and removing all non-alphanumeric characters.
      • Compute
        primary_file_path
        by taking the first entry in
        code_paths
        and stripping any line number suffixes (e.g., converting
        src/auth.c:120
        to
        src/auth.c
        ).
      • Snapshot-aware cap (value shape
        {count, last_snapshot}
        ):
        store each cache value as an object
        {count, last_snapshot}
        . When reading a value V: if V is a bare integer, treat count=V and last_snapshot=UNKNOWN; if V is an object, use V.count / V.last_snapshot (default UNKNOWN). Before incrementing, run Block B comparing the finding's snapshot to the current SNAPSHOT_ID: reset
        count=0
        ONLY when Block B is NOT_MATCHED because the two snapshots are present and actually differ (a genuine code change earns a fresh budget). Do NOT reset on UNKNOWN (absent/
        pass_
        /unpinned) — that would make no-VCS targets retry forever. Additionally keep an absolute per-finding-id attempt counter that is NEVER reset, and stop retrying once it reaches a hard ceiling (e.g. 6) regardless of snapshot changes.
    • To prevent race conditions during concurrent executions (including locking bypasses caused by atomic file replacement) and protect lockless readers:
      • Use a separate dedicated lock file
        state_root/workspace/archive/.repro_attempts.lock
        which is never deleted or replaced.
      • Perform updates atomically using Python's
        fcntl.flock
        on this lock file:
      • Open the lock file
        state_root/workspace/archive/.repro_attempts.lock
        (creating it if missing) and acquire an exclusive lock (
        fcntl.flock
        with
        fcntl.LOCK_EX
        ) inside a context manager (
        with
        statement).
      • Read the current contents of the cache file
        state_root/workspace/archive/.repro_attempts.json
        (treating it as
        {}
        if missing or empty).
      • Increment the
        count
        field of this finding's cache-key entry — keyed by
        signature
        if present, else
        stable_key
        , the SAME key selection defined above (the
        {count, last_snapshot}
        object) — by 1 ONLY for Tier-3 (full end-to-end sandboxed service) executions. Internal Tier-1 and Tier-2 stepping-stone trials MUST NOT increment
        count
        (they are governed by the sub-budget rule in Step 3).
      • Write the updated JSON to a temporary file in the same directory (e.g.,
        state_root/workspace/archive/.repro_attempts.json.tmp
        ).
      • Atomically replace the target cache file with the temporary file (e.g.,
        os.replace
        in Python) to ensure readers never see a truncated or incomplete file.
      • Close the lock file descriptor to release the lock (automatically handled by exiting the
        with
        context manager).
    Depending on whether the
    --reattack
    flag is provided:
    • If run normally (no
      --reattack
      flag):
      You must append or update the following on the existing object:
      • "repro_status"
        (
        "reproduced"
        ,
        "statically_confirmed"
        ,
        "not_attempted"
        , or
        "failed_to_reproduce"
        ).
      • "repro_file_path"
      • "run_command"
      • "repro_output"
      • "repro_snapshot_id"
        : the current SNAPSHOT_ID this run executed against.
      • "repro_hints"
        : Record compilation and sandbox execution telemetry (e.g.,
        sanitizers_used: ASan+UBSan
        ,
        assertions_disabled: true
        ,
        build_profile: release
        ) to provide empirical execution evidence for
        /mantis-critic
        .
      • If reproduction succeeds (
        repro_status
        is evaluated as
        "reproduced"
        or
        "statically_confirmed"
        ) and the finding's current
        "status"
        is
        "PROVISIONALLY_VALID"
        : BEFORE upgrading, scan the finding's
        triage_checklist
        (if present). If ANY entry has
        outcome == "UNKNOWN"
        (or
        passes == false
        ), do NOT upgrade: leave
        status
        as
        "PROVISIONALLY_VALID"
        , still set
        repro_status
        to the success value (reproduction DID succeed), and append a history note
        upgrade-to-VALID-blocked: triage_checklist has UNKNOWN entries (re-review required)
        . This avoids violating the schema's
        VALID ⇒ no UNKNOWN
        allOf gate (schema.json lines 471-507), which forbids
        UNKNOWN
        /
        passes:false
        on any
        VALID
        non-chain finding's
        triage_checklist
        . Reproduce does NOT touch
        triage_checklist
        entries (the checklist is review's artifact; only review may resolve
        UNKNOWN
        entries). If
        triage_checklist
        is absent (no
        reviewer
        history entry, e.g. a legacy finding), or NO entry is
        UNKNOWN
        /
        passes:false
        , you must update
        "status"
        to
        "VALID"
        .
      • An entry to the
        "history"
        array:
      json
      {
        "stage": "reproduce",
        "action": "reproduced",
        "details": "Reproduction status evaluated as [reproduced/failed_to_reproduce] using command: [run_command]",
        "pass_number": <current_pass_number>,
        "timestamp": "<current_iso8601_timestamp>"
      }
    • If run with
      --reattack
      :
      You must append or update the following on the existing object (do not touch
      repro_*
      or
      status
      ):
      • "reattack_status"
        (
        "bypassed_patch"
        ,
        "failed_to_bypass"
        ,
        "inconclusive_baseline_changed"
        ).
      • "bypassed_patch"
        : The PoC bypassed the patch and triggered the bug. If
        patch_status
        is
        VERIFIED_SECURE
        , atomically set
        patch_status = "VERIFICATION_FAILED"
        in the same write (a bypass defeats the patch). This is an explicit exception to "do not touch status" and applies to both the C5 step-3 path and same-snapshot runs.
      • "failed_to_bypass"
        : The PoC was run but failed to bypass the patch. (No downgrade needed —
        failed_to_bypass
        is the value the allOf gate requires for
        VERIFIED_SECURE
        .)
      • "inconclusive_baseline_changed"
        : The unpatched baseline was re-run (see C5 below) and the bug NO LONGER TRIGGERS on the current unpatched code. Do NOT claim
        failed_to_bypass
        . If
        patch_status
        is
        VERIFIED_SECURE
        , atomically set
        patch_status = "VERIFICATION_INCOMPLETE"
        in the same write.
      • INV-1 (single source — the schema's
        VERIFIED_SECURE
        allOf gate):
        VERIFIED_SECURE => reattack_status
        must be
        failed_to_bypass
        , and
        failed_to_bypass
        requires a non-empty
        reattack_variants
        array with ≥ 3 valid variant inputs (Step 3a) that ALL failed to trigger the bug on the patched shadow. An empty or short variant set makes "all failed" vacuously true — this is FORBIDDEN: cap at
        VERIFICATION_INCOMPLETE
        instead. Any other outcome MUST atomically downgrade
        patch_status
        in the same write —
        VERIFICATION_INCOMPLETE
        for
        inconclusive_baseline_changed
        or an insufficient variant set,
        VERIFICATION_FAILED
        for
        bypassed_patch
        . Never persist
        VERIFIED_SECURE
        alongside a non-
        failed_to_bypass
        reattack_status
        .
      • Snapshot-mismatch -> governed by C5 below: When
        reattack_snapshot_id
        !=
        repro_snapshot_id
        , do NOT independently record a verdict — follow C5, which re-establishes the unpatched baseline on the CURRENT snapshot. If C5 cannot run, fall back to leaving
        reattack_status
        UNSET with a
        SNAPSHOT_MISMATCH
        history note.
      • C5 — Unpatched-baseline re-run (Phase 2): Before running the attack on the patched build, if
        reattack_snapshot_id
        !=
        repro_snapshot_id
        (a genuine snapshot change, NOT a HALT-mode
        live:
        tree), FIRST re-establish the unpatched baseline:
        1. Run the reproducer against a FRESH UNPATCHED copy of the current snapshot — a fresh
          mktemp -d
          copy of
          active_snapshot.root
          , NOT the patched shadow. (This is the same unpatched baseline that
          mantis-patch
          Block G step 1 runs; reproduce has no Block G.)
        2. If the unpatched baseline does NOT trigger (evidence absent per Block F): set
          reattack_status = "inconclusive_baseline_changed"
          , do NOT proceed with the attack, do NOT claim
          failed_to_bypass
          . You MUST still populate
          reattack_file_path
          ,
          reattack_run_command
          , and
          reattack_output
          with the baseline re-run's details. Apply INV-1 (downgrade
          VERIFIED_SECURE
          ->
          VERIFICATION_INCOMPLETE
          ).
        3. If the unpatched baseline DOES trigger: proceed with the attack (
          bypassed_patch
          or
          failed_to_bypass
          ). Apply INV-1 (downgrade
          VERIFIED_SECURE
          ->
          VERIFICATION_FAILED
          if
          bypassed_patch
          ).
        • Sanitizer consistency: the baseline re-run, attack, and re-attack MUST use the same sanitizer flags that made the original baseline trigger. If the baseline triggered via UBSan (exit 0), recompiling the attack without UBSan would mask the bug and produce a false negative (INV-2) or false
          failed_to_bypass
          (INV-1).
        • HALT-mode guardrail: Detect HALT by the PASS's snapshot id in state (
          active_snapshot.snapshot_id
          starts with
          live:
          ), NOT the
          --snapshot_pinned=false
          argument (that's only the sentinel-exemption for the patched shadow). In HALT, skip C5 and follow the existing HALT ceiling (leave
          reattack_status
          UNSET with the HALT note).
        • This does NOT change the VERIFIED_SECURE gate — Block G still requires the unpatched baseline to trigger.
      • "reattack_file_path"
      • "reattack_run_command"
      • "reattack_output"
      • "reattack_variants"
        : An array of objects, one per variant input attempted during Step 3a. Each object MUST contain EXACTLY the two required keys
        "description"
        (string) and
        "triggered"
        (boolean). Do NOT invent free-form or custom keys (such as
        input
        ,
        result
        ,
        bypassed
        ,
        label
        ,
        name
        ):
        json
        "reattack_variants": [
          {
            "description": "off-by-one: len=bound+1",
            "triggered": false
          },
          {
            "description": "alternate path via /api/v2/echo",
            "triggered": false
          },
          {
            "description": "boundary mutation: max INT_MAX",
            "triggered": false
          }
        ]
        • "description"
          : What the variant does (e.g.,
          "off-by-one: len=bound+1"
          ,
          "alternate path via /api/v2/echo"
          ).
        • "triggered"
          : boolean — whether this variant triggered the original vulnerability class on the patched shadow (per the variant validity guardrail in Step 3a). Invalid/junk mutants that produced an unrelated crash or error are recorded as
          triggered = false
          with a description noting invalidity.
          reattack_variants
          MUST be non-empty (≥ 3 entries) for
          reattack_status = "failed_to_bypass"
          . An empty array
          []
          may ONLY coexist with a non-
          failed_to_bypass
          status (e.g., C5 baseline failure that halted before variant hunting, or
          inconclusive_baseline_changed
          ).
      • "reattack_snapshot_id"
        : the current SNAPSHOT_ID this run executed against.
      • An entry to the
        "history"
        array:
      json
      {
        "stage": "reattack",
        "action": "reproduced",
        "details": "Re-attack status evaluated as [bypassed_patch/failed_to_bypass] using command: [reattack_run_command]",
        "pass_number": <current_pass_number>,
        "timestamp": "<current_iso8601_timestamp>"
      }
  4. Criticism of Reproduction Validity: To ensure the reproduction is a valid example of reproducing the reported vulnerability, have a subagent with a fresh context window review and criticize the generated PoC. Seek genuine criticism to ensure false reports are never surfaced later.
    Variant criticism (re-attack only): When
    --reattack
    is specified, the critic subagent MUST also verify that the variant inputs (Step 3a) are genuinely diverse — not trivially identical mutations (e.g., changing a comment while keeping the same payload). If the critic finds the variants are not meaningfully diverse, record a history note
    variant_diversity_insufficient
    and re-author variants before finalizing
    reattack_status
    .
When complete, notify the user.
当使用
--reattack
调用时,除了重新运行原始PoC之外,您还必须编写并执行N ≥ 3个边界变异的变体输入。模式(
schema.json
)字面将其称为"变体搜索重攻击"——仅重新运行原始PoC是不够的。仅防护确切PoC字节的过窄补丁是自动修复的主要失败模式;变体搜索是无需额外基础设施成本的防御措施。
旧漏洞发现结果: 缺少
reattack_variants
的漏洞发现结果(在此规则存在之前创建)会在首次
--reattack
运行时按照≥3个变体的要求重新验证。这是有意为之的——旧的
VERIFIED_SECURE
结论会升级到更严格的标准——但预计在首次运行变体搜索时,归档的漏洞发现结果会出现一次性变动。
要生成的变体(针对漏洞类型):
  • 内存安全漏洞(缓冲区溢出、越界读/写、UAF、整数溢出): 编写至少3种以下变体:
    • 差一错误:
      len = bound
      len = bound + 1
      len = bound - 1
    • 大小变异:
      len ± 1
      len = 0
      len = SIZE_MAX
      、有符号长度的符号翻转。
    • 到达同一漏洞点的替代路径: 如果漏洞点可通过多个调用点到达,编写通过不同路径到达的变体(例如不同的API端点、文件格式变体或协议命令)。
    • 类型混淆/宽度不匹配: 利用到达同一漏洞点的不同类型路径。
  • 非内存安全漏洞(逻辑、授权、注入、SSRF、路径遍历): 搜索同一类型的实际变体:
    • 替代端点/参数: 当PoC针对
      /api/v1/echo
      时,尝试
      /api/v2/echo
      ,或使用替代参数名称。
    • 等效载荷:
      ..%2fetc%2fpasswd
      ..\\..\\
      、URL编码、双重编码、Unicode规范化变体。
    • 授权边界变体: 不同角色、空/Null令牌、替代权限提升路径。
    • 注入变体:
      '; EXEC--
       UNION SELECT
      、盲注变体、替代注入点。
  • 并行变体生成(如果有子代理可用): 您应该生成子代理来并行编写和测试变体。每个子代理采用一种变异策略,编写其变体PoC,并报告是否触发漏洞。在设置
    reattack_status
    之前汇总所有结果。如果没有子代理可用,则按顺序执行。
执行: 将每个变体作为单独的脚本写入
state_root/workspace/reproducers/
(例如
reattack_variant_[uuid]_[N].py
)。使用与步骤3相同的隔离约束,针对已修补副本(
--target_root
)执行每个变体。使用完全符合模式的键
{"description": "...", "triggered": true/false}
reattack_variants
数组中记录每个变体(步骤6)。
结论规则:
reattack_status = "failed_to_bypass"
需要非空的
reattack_variants
数组,其中包含≥3个在已修补副本上均未触发漏洞的有效变体输入。空数组或数量不足会使"所有变体失败"在逻辑上成立——这是被禁止的:如果经过真正努力仍无法构建3个有意义的变体,则将结论设为
VERIFICATION_INCOMPLETE
(历史记录备注
insufficient_variants
),绝不能设为
failed_to_bypass
[]
情况只能与非
failed_to_bypass
的状态共存(例如C5基线失败导致变体搜索提前终止)。
变体有效性护栏: 变体被视为绕过(
triggered = true
导致
bypassed_patch
)仅当同时满足以下两个条件:
  1. 相同漏洞类型: 变体复现了原始漏洞类型——相同的漏洞点函数/Sanitizer签名/崩溃类型。无效变异体(例如
    len=SIZE_MAX
    导致无关的OOM、替代端点404后报错、或完全不同的崩溃)不算作绕过。丢弃它(设置
    triggered = false
    并在描述中注明无效)并继续。对于非内存漏洞(逻辑、授权、注入),比较相同的漏洞点函数或行为(例如相同的未授权操作成功、相同的注入执行、到达相同的漏洞点函数)——而非与补丁前的行号进行±行比较(补丁会移动行号,且非内存漏洞通常没有精确的漏洞点行号)。如果无法确定触发变体是不同的漏洞,则将其视为绕过(故障关闭:优先选择假VERIFICATION_FAILED而非假VERIFIED_SECURE)。
  2. 符合步骤4的有效输入: 变体必须是对公共API或内部不变量的有效使用——不得依赖绕过库执行不变量的人工工具技巧(例如使用自定义分配的缓冲区直接调用私有/静态函数)。
理想情况下,确认每个触发变体在未修补副本(原始PoC运行的相同基线)上仍能触发,以证明它利用的是原始漏洞而非工件。如果未修补副本不可用(例如快照不匹配),则需要相同漏洞点的证据(相同的Sanitizer帧、相同的崩溃地址、相同的逻辑失败)作为佐证。
如果任何有效变体触发了漏洞,则设置
reattack_status = "bypassed_patch"
并应用INV-1(将
VERIFIED_SECURE
降级为
VERIFICATION_FAILED
)。
  • 复现状态分类:
    • reproduced
      :PoC成功触发了漏洞。
    • failed_to_reproduce
      :PoC已执行但未触发漏洞。
    • statically_confirmed
      :由于环境约束(例如缺少硬件模拟器、外部服务不可用)无法复现,但漏洞在静态分析中明显存在(例如硬编码凭证)。强烈不建议使用此状态,仅作为最后手段。
    • not_attempted
      :复现阶段被完全跳过(例如由于基础设施设置失败、超时或显式跳过配置)。
  1. 严格的公共API与内部不变量约束:
    • 崩溃复现器应尽可能通过面向公众的API与代码库交互,或严格遵守库的全局执行不变量(例如分配器填充),以避免生成人工的、不可行的崩溃。
    • 如果只能通过编译直接调用工具(向私有/静态函数提供自定义分配的缓冲区,例如
      malloc(15)
      )来触发崩溃,而绕过了库的保证分配器包装器(例如
      png_malloc(rowbytes + 48)
      ),则不得将漏洞发现结果声明为"reproduced"。
    • 如果无法通过公共API或标准分配填充触发崩溃,则将漏洞发现结果分类为
      "failed_to_reproduce"
      ,原因是"Internal Invariant Protection"。
  2. 功能与崩溃感知验证: 分析输出(如stdout、stderr和退出码),根据漏洞类型对复现成功情况进行分类:
在对任何负面结果(
failed_to_reproduce
,或
--reattack
模式下的
failed_to_bypass
)进行分类之前,应用以下门限:
REACHED-SINK EVIDENCE GATE (mechanical):
Each reproducer produces REACHED-SINK EVIDENCE via ONE channel, recorded in repro_hints:
   (a) script/source harness -> write the exact bytes MANTIS_REACHED_ENTRYPOINT to a
       sidecar file $SENTINEL_FILE and flush+fsync (or unbuffered write) BEFORE
       invoking the sink. (A file survives a crash that truncates buffered stdout.)
   (b) binary / firmware / raw-payload -> reached-sink evidence is a captured
       crash backtrace or sanitizer frame (ASan/UBSan/MSan/TSan) that
       explicitly names the target sink function (target-produced tracing). A
       marker written by a wrapper you author BEFORE invoking the target is
       SETUP EVIDENCE ONLY: it proves "launch attempted," not "sink reached,"
       and does NOT qualify as reached-sink evidence. If no in-path marker
       (channel a) and no target-produced backtrace/sanitizer trace
       (channel b) is achievable, the sink is unreached.
EVIDENCE PRESENT (reached-sink) = (channel a) sidecar file contains
   MANTIS_REACHED_ENTRYPOINT written in-path, OR (channel b) target-produced
   backtrace/sanitizer output names the sink. A wrapper pre-launch marker alone is
   NOT evidence present.
EVIDENCE ABSENT includes: any compiler/build nonzero exit; exit 127 (command not
  found); exit 2 with a "No such file" message.
DECISION GATE (gate the DECISION, not specific verdict strings):
  - Record repro_status = reproduced OR statically_confirmed ONLY if EVIDENCE is
    PRESENT. If ABSENT -> repro_status = not_attempted (retry-eligible), STOP.
  - In patch verification, EVIDENCE is required on the UNPATCHED baseline (Block G),
    NOT on the post-patch attack run (a correct patch legitimately stops the input
    before the sink).
  - If NO evidence channel is achievable for this target, downgrade to
    not_attempted / VERIFICATION_INCOMPLETE. NEVER synthesize the marker.
具体来说:如果运行未产生任何到达漏洞点的证据(构建/设置错误、退出码127、"No such file"或从未到达漏洞点),则记录
repro_status = not_attempted
(可重试)——绝不能记录
failed_to_reproduce
;在
--reattack
模式下,保持
reattack_status
未设置,并添加历史记录备注"setup_failed"——绝不能记录
failed_to_bypass
。只有当工具已证明到达漏洞入口点且漏洞未触发时,才分类为负面结果。
HALT上限(三态规则): 如果状态中存在
active_snapshot
snapshot_pinned
false
(HALT模式——代码树已过期或无法固定),则您完全不得记录
failed_to_reproduce
failed_to_bypass
。在HALT模式下,代码可能已漂移,负面复现结果无法作为权威结论。相反,记录
repro_status = not_attempted
(可重试),并在
--reattack
模式下保持
reattack_status
未设置,添加历史记录备注"HALT mode: snapshot unpinned, negative result suppressed"。这与适用于HALT模式下所有阶段的权威结论禁止规则一致。(在MODE-OFF模式下——无
active_snapshot
——正常分类负面结果。)
  • 逻辑与授权漏洞: 成功的复现器是一个功能单元测试或脚本,可明确展示逻辑失败(例如未授权请求返回
    200 OK
    ,或测试脚本成功绕过验证并以
    0
    退出)。
  • 内存安全与二进制崩溃: 如果沙箱执行在stdout/stderr中产生崩溃信号或Sanitizer跟踪,则将复现标记为
    "reproduced"
    无论退出码如何,都要扫描stdout/stderr以查找Sanitizer签名——UBSan默认使用恢复模式(退出码0),因此退出码0的运行仍可能包含证明漏洞触发的有效UBSan跟踪。检查以下内容:
    • AddressSanitizer (ASan)错误输出(例如
      ERROR: AddressSanitizer
      )。
    • UndefinedBehaviorSanitizer (UBSan)运行时报告(例如
      runtime error:
      SUMMARY: UndefinedBehaviorSanitizer
      )。
    • MemorySanitizer (MSan)错误输出(例如
      WARNING: MemorySanitizer
      )。仅当
      repro_hints
      记录存在完全检测的MSan构建时,MSan证据才有效
      (步骤3注意事项)。未完全检测的简单
      -fsanitize=memory
      构建会产生虚假跟踪——请勿将这些分类为
      "reproduced"
    • ThreadSanitizer (TSan)竞争报告(例如
      WARNING: ThreadSanitizer
      )。
    • 段错误(SIGSEGV,退出码
      139
      )。
    • 中止信号(SIGABRT,退出码
      134
      )。
    • 崩溃或核心转储。
  1. 令牌优化的文件更新: 为了最小化LLM输出令牌,请勿在输出中重新发出或手动重写整个JSON对象。相反,使用就地编辑工具(例如您偏好语言的短脚本,或
    jq
    )以编程方式将新字段追加到现有的
    state_root/workspace/findings/<id>.json
    文件中。
此外,您必须更新复现尝试缓存,以帮助规划器高效跟踪尝试次数:
  • state_root/workspace/archive/.repro_attempts.json
    维护一个JSON缓存文件。在创建、读取或锁定缓存文件之前,确保父目录
    state_root/workspace/archive/
    存在(例如
    mkdir -p state_root/workspace/archive/
    )。
  • 使用稳定标识符作为缓存键,即使UUID重新生成,该标识符也会在循环运行中保持不变。如果漏洞发现结果有
    signature
    字段,则直接将其用作缓存键(它已经是确定性的内容身份哈希)。如果
    signature
    不存在,则使用漏洞发现结果的规范化标题及其主文件路径计算稳定键:
    stable_key = normalized_title + "@" + primary_file_path
    • 计算
      normalized_title
      :将标题转换为小写并删除所有非字母数字字符。
    • 计算
      primary_file_path
      :取
      code_paths
      中的第一个条目并删除任何行号后缀(例如将
      src/auth.c:120
      转换为
      src/auth.c
      )。
    • 快照感知上限(值格式
      {count, last_snapshot}
      ):
      将每个缓存值存储为对象
      {count, last_snapshot}
      。读取值V时:如果V是纯整数,则视为count=V且last_snapshot=UNKNOWN;如果V是对象,则使用V.count / V.last_snapshot(默认UNKNOWN)。在递增之前,运行Block B比较漏洞发现结果的快照与当前SNAPSHOT_ID:仅当Block B返回NOT_MATCHED 且两个快照均存在且实际不同(真实代码变更获得新的预算)时,重置
      count=0
      。请勿在UNKNOWN(缺失/
      pass_
      /未固定)时重置——这会导致无VCS的目标无限重试。此外,保留每个漏洞发现结果ID的绝对尝试计数器,该计数器永远不会重置,一旦达到硬上限(例如6),无论快照如何变化,都停止重试。
  • 为防止并发执行期间的竞争条件(包括原子文件替换导致的锁绕过)并保护无锁读取器:
    • 使用单独的专用锁文件
      state_root/workspace/archive/.repro_attempts.lock
      ,该文件永远不会被删除或替换。
    • 使用Python的
      fcntl.flock
      对该锁文件执行原子性更新:
    • 打开锁文件
      state_root/workspace/archive/.repro_attempts.lock
      (如果缺失则创建),并在上下文管理器(
      with
      语句)内获取排他锁(
      fcntl.flock
      搭配
      fcntl.LOCK_EX
      )。
    • 读取缓存文件
      state_root/workspace/archive/.repro_attempts.json
      的当前内容(如果缺失或为空,则视为
      {}
      )。
    • 仅针对第3层(完整端到端沙箱服务)执行,将此漏洞发现结果的缓存键条目的
      count
      字段(如果存在
      signature
      则使用
      signature
      作为键,否则使用
      stable_key
      ,即上述定义的相同键选择,
      {count, last_snapshot}
      对象)递增1。内部第1层和第2层垫脚石试验不得递增
      count
      (它们受步骤3中的子预算规则约束)。
    • 将更新后的JSON写入同一目录下的临时文件(例如
      state_root/workspace/archive/.repro_attempts.json.tmp
      )。
    • 原子性地将目标缓存文件替换为临时文件(例如Python中的
      os.replace
      ),以确保读取器永远不会看到截断或不完整的文件。
    • 关闭锁文件描述符以释放锁(退出
      with
      上下文管理器时自动处理)。
根据是否提供
--reattack
标志:
  • 常规运行(无
    --reattack
    标志):
    您必须在现有对象上追加或更新以下内容:
    • "repro_status"
      "reproduced"
      "statically_confirmed"
      "not_attempted"
      "failed_to_reproduce"
      )。
    • "repro_file_path"
    • "run_command"
    • "repro_output"
    • "repro_snapshot_id"
      :本次运行所针对的当前SNAPSHOT_ID。
    • "repro_hints"
      :记录编译和沙箱执行遥测数据(例如
      sanitizers_used: ASan+UBSan
      assertions_disabled: true
      build_profile: release
      ),为
      /mantis-critic
      提供实证执行证据。
    • 如果复现成功(
      repro_status
      被评估为
      "reproduced"
      "statically_confirmed"
      )且漏洞发现结果当前的
      "status"
      "PROVISIONALLY_VALID"
      :在升级之前,扫描漏洞发现结果的
      triage_checklist
      (如果存在)。如果任何条目有
      outcome == "UNKNOWN"
      (或
      passes == false
      ),则不要升级:保持
      status
      "PROVISIONALLY_VALID"
      ,仍将
      repro_status
      设置为成功值(复现确实成功),并追加历史记录备注
      upgrade-to-VALID-blocked: triage_checklist has UNKNOWN entries (re-review required)
      。这避免违反模式中
      VALID ⇒ no UNKNOWN
      的allOf约束(schema.json第471-507行),该约束禁止任何
      VALID
      非链式漏洞发现结果的
      triage_checklist
      中存在
      UNKNOWN
      /
      passes:false
      条目。复现阶段不会修改
      triage_checklist
      条目(检查列表是评审阶段的工件;只有评审阶段可以解决
      UNKNOWN
      条目)。如果
      triage_checklist
      不存在(无
      reviewer
      历史记录条目,例如旧漏洞发现结果),或没有条目为
      UNKNOWN
      /
      passes:false
      ,则您必须
      "status"
      更新为
      "VALID"
    • "history"
      数组添加一个条目:
    json
    {
      "stage": "reproduce",
      "action": "reproduced",
      "details": "Reproduction status evaluated as [reproduced/failed_to_reproduce] using command: [run_command]",
      "pass_number": <current_pass_number>,
      "timestamp": "<current_iso8601_timestamp>"
    }
  • 使用
    --reattack
    运行:
    您必须在现有对象上追加或更新以下内容(不要修改
    repro_*
    status
    ):
    • "reattack_status"
      "bypassed_patch"
      "failed_to_bypass"
      "inconclusive_baseline_changed"
      )。
    • "bypassed_patch"
      :PoC绕过补丁并触发漏洞。如果
      patch_status
      VERIFIED_SECURE
      ,则在同一写入操作中原子性设置
      patch_status = "VERIFICATION_FAILED"
      (绕过补丁会使补丁失效)。这是"不要修改状态"规则的明确例外,适用于C5步骤3路径和同快照运行。
    • "failed_to_bypass"
      :PoC已运行但未能绕过补丁。(无需降级——
      failed_to_bypass
      VERIFIED_SECURE
      的allOf约束所需的值。)
    • "inconclusive_baseline_changed"
      :重新运行未修补基线(见下文C5),且漏洞在当前未修补代码上不再触发。请勿声明
      failed_to_bypass
      。如果
      patch_status
      VERIFIED_SECURE
      ,则在同一写入操作中原子性设置
      patch_status = "VERIFICATION_INCOMPLETE"
    • INV-1(单一来源——模式的
      VERIFIED_SECURE
      allOf约束):
      VERIFIED_SECURE => reattack_status
      必须为
      failed_to_bypass
      ,且
      failed_to_bypass
      要求非空的
      reattack_variants
      数组包含≥3个在已修补副本上均未触发漏洞的有效变体输入(步骤3a)。空数组或数量不足会使"所有变体失败"在逻辑上成立——这是被禁止的:改为设为
      VERIFICATION_INCOMPLETE
      。任何其他结果必须在同一写入操作中原子性降级
      patch_status
      ——对于
      inconclusive_baseline_changed
      或变体集不足,设为
      VERIFICATION_INCOMPLETE
      ;对于
      bypassed_patch
      ,设为
      VERIFICATION_FAILED
      。永远不要在
      reattack_status
      failed_to_bypass
      的情况下保留
      VERIFIED_SECURE
    • 快照不匹配 -> 由下文C5管理:
      reattack_snapshot_id
      !=
      repro_snapshot_id
      时,不要独立记录结论——遵循C5,它会在当前快照上重新建立未修补基线。如果无法运行C5,则退而保持
      reattack_status
      未设置,并添加
      SNAPSHOT_MISMATCH
      历史记录备注。
    • C5 — 未修补基线重新运行(阶段2): 在已修补构建上运行攻击之前,如果
      reattack_snapshot_id
      !=
      repro_snapshot_id
      (真实快照变更,而非HALT模式的
      live:
      树),首先重新建立未修补基线:
      1. 针对当前快照的全新未修补副本运行复现器——
        active_snapshot.root
        的全新
        mktemp -d
        副本,而非已修补副本。(这与
        mantis-patch
        Block G步骤1运行的未修补基线相同;复现阶段没有Block G。)
      2. 如果未修补基线未触发(根据Block F证据缺失):设置
        reattack_status = "inconclusive_baseline_changed"
        ,不要继续攻击,不要声明
        failed_to_bypass
        。您仍必须使用基线重新运行的详细信息填充
        reattack_file_path
        reattack_run_command
        reattack_output
        。应用INV-1(将
        VERIFIED_SECURE
        降级为
        VERIFICATION_INCOMPLETE
        )。
      3. 如果未修补基线确实触发:继续攻击(
        bypassed_patch
        failed_to_bypass
        )。应用INV-1(如果
        bypassed_patch
        ,将
        VERIFIED_SECURE
        降级为
        VERIFICATION_FAILED
        )。
      • Sanitizer一致性: 基线重新运行、攻击运行和重攻击运行必须使用使原始基线触发的相同Sanitizer标志。如果基线通过UBSan触发(退出码0),在攻击运行时不使用UBSan重新编译会掩盖漏洞并产生假阴性(INV-2)或假
        failed_to_bypass
        (INV-1)。
      • HALT模式护栏: 通过状态中PASS的快照ID(
        active_snapshot.snapshot_id
        live:
        开头)检测HALT模式,而非
        --snapshot_pinned=false
        参数(这仅针对已修补副本的标记豁免)。在HALT模式下,跳过C5并遵循现有的HALT上限(保持
        reattack_status
        未设置并添加HALT备注)。
      • 这不会改变VERIFIED_SECURE约束——Block G仍要求未修补基线触发。
    • "reattack_file_path"
    • "reattack_run_command"
    • "reattack_output"
    • "reattack_variants"
      :一个对象数组,对应步骤3a中尝试的每个变体输入。每个对象必须包含完全符合要求的两个键
      "description"
      (字符串)和
      "triggered"
      (布尔值)。请勿发明自由格式或自定义键(例如
      input
      result
      bypassed
      label
      name
      ):
      json
      "reattack_variants": [
        {
          "description": "off-by-one: len=bound+1",
          "triggered": false
        },
        {
          "description": "alternate path via /api/v2/echo",
          "triggered": false
        },
        {
          "description": "boundary mutation: max INT_MAX",
          "triggered": false
        }
      ]
      • "description"
        :变体的操作(例如
        "off-by-one: len=bound+1"
        "alternate path via /api/v2/echo"
        )。
      • "triggered"
        :布尔值——该变体是否在已修补副本上触发了原始漏洞类型(根据步骤3a中的变体有效性护栏)。产生无关崩溃或错误的无效/垃圾变异体记录为
        triggered = false
        ,并在描述中注明无效。
        reattack_variants
        必须非空(≥3个条目)才能设置
        reattack_status = "failed_to_bypass"
        。空数组
        []
        只能与非
        failed_to_bypass
        的状态共存(例如C5基线失败导致变体搜索提前终止,或
        inconclusive_baseline_changed
        )。
    • "reattack_snapshot_id"
      :本次运行所针对的当前SNAPSHOT_ID。
    • "history"
      数组添加一个条目:
      json
      {
        "stage": "reattack",
        "action": "reproduced",
        "details": "Re-attack status evaluated as [bypassed_patch/failed_to_bypass] using command: [reattack_run_command]",
        "pass_number": <current_pass_number>,
        "timestamp": "<current_iso8601_timestamp>"
      }
  1. 复现有效性评审: 为确保复现是所报告漏洞的有效示例,请让具有全新上下文窗口的子代理评审并批评生成的PoC。寻求真实的评审意见,以确保不会在后续出现虚假报告。
    变体评审(仅重攻击时需要): 当指定
    --reattack
    时,评审子代理还必须验证变体输入(步骤3a)是否真正多样化——而非微不足道的相同变异(例如修改注释而保持载荷不变)。如果评审发现变体没有有意义的多样性,则记录历史记录备注
    variant_diversity_insufficient
    ,并在最终确定
    reattack_status
    之前重新编写变体。
完成后,通知用户。