mantis-chain
Analyzes individual security findings to identify and construct complex exploit chains. Use after validation stages to see if multiple low-severity bugs can be combined into a higher impact vulnerability. Don't use for initial codebase auditing or writing patch code.
By google · 995 installs
npx skills add google/mantis --skill mantis-chain
Source repository · Upstream listing
Vulnerability Chainer (/mantis chain)
System Goal
Exploit Chain Architect. Analyzes isolated, individually validated security
findings and historical knowledge base primitives to identify and construct
complex, multi step exploit chains.
Command Definition
Command: /mantis chain
Description: Analyzes individual security findings to identify and
construct complex exploit chains.
Arguments (all optional; supplied by the orchestrator per the harness
lifecycle contract — see schema.json "Non JSON Contracts"):
snapshot root / SNAPSHOT ROOT — the pinned, immutable code snapshot
root for this pass. Consumed by Block A.
snapshot id / SNAPSHOT ID — the snapshot identity string for this
pass. Consumed by Block A (sentinel) and Block B (match check).
state root — parent directory of workspace/ . When absent, defaults to
the current directory (Block A step 1c/1d).
target root — an already prepared tree that OVERRIDES the snapshot root
(rarely used by this stage; honored by Block A step 1a). When NONE of these
are passed, Block A falls back to active snapshot in
workspace/.mantis state.json ; if that is absent too, the stage runs
MODE OFF ( snapshot pinned = false ) and behaves exactly as today (see
Backward compat).
Input/Output Contract
Reads :
workspace/findings/ (validated finding JSON files where status is
"VALID" , and viability is "VIABLE" , "CONDITIONAL VIABLE" , or
"SAMPLE OR TEST" ).
workspace/kb/entities/ .md and workspace/kb/vulnerabilities/ .md
(knowledge base primitives).
workspace/.mantis state.json (to track current loop pass).
Writes :
Net new exploit chain finding JSON files to
workspace/findings/<new uuid .json . Original findings are left unmodified.
Preconditions :
Validated or viable findings must exist in workspace/findings/ .
Idempotency Guarantee :
Before writing a new exploit chain finding, the skill must check existing
exploit chain findings by comparing the constituent finding sequence. Scan
BOTH the current workspace/findings/ directory AND every archived pass
under workspace/archive/findings pass / AND legacy
workspace/archive/loop findings/ (all STATE RELATIVE — never prefix
CODE ROOT ). A chain JSON is any finding whose constituent findings array
is present and non empty. If a chain with the EXACT same ordered constituent
sequence already exists in EITHER location, skip creating a duplicate.
Signature keyed idempotency (preferred) — with a code paths tiebreak: If
ALL constituent findings have a signature field, compare the ordered
constituent signature sequence (not UUIDs). Treat two chains as the SAME
(and skip creating the new one) ONLY IF their ordered signature sequences
are equal AND, for each corresponding constituent pair, at least one
code paths entry (line inclusive, i.e. compared WITH its trailing :line )
is identical. If the signature sequences match but any corresponding
constituent's code paths differ, the chains are DISTINCT — create the new
chain. (Over reporting is safe; a signature collision must never suppress
a genuinely new exploit chain, because signature strips line numbers and
can collide between distinct same file bugs.)
UUID fallback (today's behavior): If ANY constituent finding lacks a
signature field, fall back to comparing the ordered constituent UUID
sequence exactly as before. This preserves today's behavior for legacy /
un upgraded findings.
This archive scan is now fully effective with stable finding signatures: two
chains whose constituents share the same signatures are correctly
deduplicated across passes. When signatures are absent (legacy findings),
the scan remains HARMLESS — it cannot falsely suppress a legitimate new
chain (no silent dropped result) and simply prevents exact UUID
re duplication within a resumed / rerun pass. If the workspace/archive/
directory does not exist, treat the archived set as empty and proceed.
Instructions
Locator Resolution (run first — all stages)
[!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).
Stage specific notes for Block A:
mantis chain is NOT a findings only stage (it is not
report/calibrate/reflect), so Block A runs steps 1–6 and resolves CODE ROOT ,
SNAPSHOT ID , and snapshot pinned from snapshot root / snapshot id
/ state active snapshot .
This stage WRITES only new finding JSON to workspace/findings/
(STATE RELATIVE, Block A step 3). It never writes under CODE ROOT , so Block
A step 4 is satisfied trivially. If you optionally re inspect a constituent's
code paths to sanity check a chain, read them SNAPSHOT RELATIVE under
CODE ROOT (Block A step 3) and never cd and write there.
A chain finding's code paths are COPIED verbatim from its constituents (they
are already SNAPSHOT RELATIVE). Do not re prefix, re resolve, or renumber
them.
Snapshot Match Check (used to select constituents)
You will run Block B once per candidate constituent finding in Step 1 below,
using that finding's discovery commit as F.discovery commit .
Read the current batch of validated findings and explore whether multiple
seemingly low severity or disparate vulnerabilities can be sequentially combined
to achieve a higher impact compromise.
Execute the chaining stage as follows:
1. Load Primitives & Validated Findings:
Read the JSON files in the workspace/findings/ directory. Filter for
findings that have passed validation (e.g., status is "VALID" and
viability is "VIABLE" , "CONDITIONAL VIABLE" , or "SAMPLE OR TEST" ).
Snapshot eligibility gate (NEW — branches on active snapshot presence,
3 state model):
MODE OFF (no active snapshot in state — no sync was requested,
today's default): SKIP this gate entirely: every finding that passed the
validation/viability filter above is an eligible constituent, exactly as
today. Build chains normally.
HALT ( active snapshot IS present but snapshot pinned == false ):
do NOT build any chains this pass. In HALT, findings' locators and
pre/post conditions may be stale (the tree raced or could not be pinned),
so no authoritative chain verdicts may be produced. Log "no chain: HALT
mode (active snapshot present, snapshot pinned=false)" and stop the
chaining stage cleanly (produce no chain files). This mirrors the
minimum eligibility guard below — a chain requires
proven against snapshot constituents, which HALT cannot provide.
PINNED ( active snapshot present AND snapshot pinned == true ): run
the Snapshot Match Check (Block B) on EACH such finding, using its
discovery commit . Keep ONLY findings that return MATCHED as
eligible constituents. A finding that returns NOT MATCHED — including
any finding whose discovery commit is absent/empty, is the literal
"MIXED" , or differs from the current SNAPSHOT ID — was discovered
against a DIFFERENT code snapshot; its file:line locators and its
pre/post conditions may no longer hold, so it MUST NOT be used as a chain
link this pass.
Minimum eligibility guard (NEW): If fewer than 2 eligible constituents
remain, do NOT construct any chain this pass — a chain requires at
least two links proven against the SAME snapshot. Log "no chain: fewer than
2 snapshot matched constituents" and stop the chaining stage cleanly (this
is not an error; simply produce no chain files). This mirrors today's
behavior whenever there are fewer than two chainable findings.
Read the Markdown Knowledge Base ( workspace/kb/entities/ and
workspace/kb/vulnerabilities/ ) to identify architectural primitives that
might not be bugs on their own, but could serve as stepping stones (e.g.,
"User controls file upload path", "Service runs as root").
2. Cross Finding Analysis (The Chaining Matrix):
Analyze the preconditions and postconditions of each validated finding.
Ask: Can the output or side effect of Finding A satisfy the strict
precondition required to trigger Finding B?
Example Chains to look for:
Path Traversal + Loose Permissions = RCE: A low severity path
traversal (Finding A) allows writing to /tmp , but a separate
misconfiguration (Finding B) allows a cron job to execute scripts in
/tmp .
XSS + CSRF = Account Takeover: A stored XSS (Finding A) can be used
to harvest an anti CSRF token to execute a state changing action (Finding
B).
Info Leak (Memory Revelation) + Buffer Overflow = ASLR Bypass: An
info leak (Finding A) reveals base pointers, satisfying the precondition
to exploit a stack buffer overflow (Finding B).
3. Construct "Super Findings":
If a viable exploit chain is discovered, do NOT modify or delete the
original isolated findings. They still need to be patched individually.
Idempotency check (run BEFORE minting a UUID): Apply the Idempotency
Guarantee above — scan current workspace/findings/ AND
workspace/archive/findings pass / AND legacy
workspace/archive/loop findings/ for a chain whose constituent sequence
equals this chain's ordered constituent sequence. If ALL constituents have
signature , compare ordered signature sequences AND require the
per constituent line inclusive code paths tiebreak described in the
Idempotency Guarantee (a signature sequence match ALONE is NOT enough to
skip); if ANY constituent lacks signature , fall back to ordered
constituent UUID sequences (today's behavior). Only if a match satisfies
the tiebreak, SKIP this chain (do not create a file) and move on to the
next candidate.
Instead, generate a net new UUID and create a new finding JSON file in
workspace/findings/<new uuid .json .
Constituent Findings : You must record the array of constituent finding
UUIDs in the structured "constituent findings" property (e.g.,
["UUID A", "UUID B"] ). This clearly documents the links of the exploit
chain.
Determine Discovery Snapshot ( discovery commit ) : Set the chain
finding's discovery commit from its ELIGIBLE constituents (the ones you
kept in Step 1):
MODE OFF short circuit (3 state rule): if active snapshot is ABSENT
in state (MODE OFF — no sync was requested), OMIT discovery commit
on the chain finding entirely. In MODE OFF, researcher OMITS
discovery commit on every constituent ( researcher:317,340 341 : "OMIT
this key entirely if active snapshot is absent or snapshot pinned is
false"), so every constituent has a missing/empty discovery commit . The
SAME/MIXED logic below would thus write the literal "MIXED" on every
chain — a snapshot era artifact that did not exist in Phase 1 and
violates MODE OFF's "byte for byte today's behavior" guarantee
( schema.json:4 ). The chain's own schema comment ( chain:307 )