Tool Family: verify
- Registration source:
tools/mcp_tools/verify.py:133 register_verify_tools(mcp, *, ctx)— discovered viacollect_tools()/register_*_toolsnaming; no edit tomcp_exploit_server.pyneeded. - Gate:
@require_allowlist()— re-executes a stored exploit probe against the finding's own asset, so the target-IP allowlist lock applies. - Purpose: Machine re-proof of a CANDIDATE finding ("verify-or-it-didn't-happen"). Reloads the finding's stored verification probe and re-runs it N times; the verdict comes solely from
tools.verify_oracle.VerifyOracle(N/Noutcome_truthcompromise proof). LLM text and exit codes never decide. Authorized-testing-only: verification probes execute attack commands against a target you own or are explicitly authorized to test.
Tools Exported (1)
| Tool | Decorator | Params | Result Shape | Notes |
|---|---|---|---|---|
verify_finding | @require_allowlist() | target_ip: str, finding_id: str, run_id: str="", repeats: int=2 | VERIFY_VERDICT: block (FINDING, TARGET, RUN, VERDICT, PROOF_RUNS, PROOF_SHA256, PROBE, EVIDENCE, DETAIL) | Reloads verification_probe from reports/<run_id>/enhanced/enhanced_report.json (latest run containing the finding when run_id is empty) and re-executes ONLY that probe N times via run_exploit_terminal in-process. Persists verify_status + verify_history[] (with proof capsule) into the finding. |
Parameters — Constraints
finding_idandtarget_ipare required; empty values returnBLOCKED: ... is required.target_ipmust equal the finding'saffected_asset(case-insensitive compare) — otherwiseBLOCKED: target_ip ... does not match the finding's affected_asset ....run_idempty means "latest run containing this finding" (newest-first scan of run dirs holding anenhanced/enhanced_report.json); unknownfinding_idreturnsERROR: verify_finding: ....repeatsis the proof-run count N (default 2, clamped 1–5); unparseable values fall back to 2. ALL N runs must show compromise proof.
Result Shape
VERIFY_VERDICT:
FINDING: F-127.0.0.1-run_exploit_terminal
TARGET: 127.0.0.1
RUN: 2026-09-07T00-00-00
VERDICT: VERIFIED
PROOF_RUNS: 2
PROOF_SHA256: <sha256 of the proof capsule>
PROBE: [shell_command] <probe command, first 300 chars>
EVIDENCE: reports/2026-09-07T00-00-00/enhanced/enhanced_report.json
DETAIL: <oracle detail, first 500 chars>
Verdicts
| Verdict | Meaning |
|---|---|
VERIFIED | All N runs show machine compromise proof. |
HOLDING | Flaky or failing proof — stays a candidate. |
INCONCLUSIVE | No stored probe, blocked/sandbox-failed run, or ambiguous output. Fail-closed; never a host fallback. |
How It Works
locate_finding(shared with retest, lives intools/mcp_tools/retest.py) loads(report_data, finding, json_path, resolved_run_id)or raisesLookupError.resolve_probereturns the storedverification_probedict, orNonewhen absent/empty — the no-probe path persistsINCONCLUSIVEwith detailno stored verification probe for this findingand returnsPROBE: (none stored).resolve_execfills{target_ip}/{target}placeholders in the probe'sexecstring, then_run_probe_in_processre-executes it via the already-registeredrun_exploit_terminaltool function in-process (tools/mcp_tools/killchain._in_process_tool_executor), so the allowlist lock, JSONL audit trail, and sandbox funnel apply unchanged. Sandbox failures surface asSANDBOX_*text and fail closed toINCONCLUSIVE.VerifyOracle.verify_sync({"exec": command}, repeats=n, run_ids=[resolved_run])produces the verdict plus a proof capsule (proof_capsule.to_dict(),.sha256,.outputs).persist_verifystampsverify_statusand appendsverify_history[](timestamp,verdict,evidence,proof_capsule) in the existing run artifact JSON, then regenerates sibling.md/.htmlreports when present (best-effort).
Dependencies
tools/mcp_tools/retest.py—locate_finding,resolve_probe,resolve_exec,_find_in_report,_read_report_json,_reports_root,_run_probe_in_process(shared probe helpers live here, not inverify.py)tools/verify_oracle.py—VerifyOracle,VERIFIED,HOLDING,INCONCLUSIVEtools/enhanced_reporting.py—EnhancedReportGeneratorfor sibling report regenerationtools/mcp_tools/killchain.py—_in_process_tool_executorfor the in-process probe run
Config
Implementation note: there is no dedicated verify: config section. The reports root resolves via _reports_root(config): config reports_dir, else the BREACHPILOT_REPORTS_DIR environment variable, else reports. The allowlist gate follows exploit.require_explicit_allowlist / exploit.allowed_targets.
Auditing
@require_allowlist() writes started then completed|blocked to exploit_audit.jsonl. The probe re-execution itself goes through run_exploit_terminal, so it is audited as its own tool call too.
Validation
target_ipmust match the finding'saffected_asset— verify runs ONLY against the finding's own asset, never an arbitrary host.repeatsclamped 1–5; all N must prove compromise.record_verifyraisesValueErroron an unknown verdict; persistence failures degrade theEVIDENCEline to<path> (persistence failed — verdict not saved)rather than failing the call.
Tests
tests/test_verify_oracle.py— oracle verdict semantics (VERIFIED/HOLDING/INCONCLUSIVE)
Related documentation
- MCP security — allowlist lock + audit trail
- MCP registration — decorator contract
- Retest tool family — the fix-proving counterpart (
STILL_OPEN/FIXED/INCONCLUSIVE)
Source map
tools/mcp_tools/verify.pytools/mcp_tools/retest.pytools/verify_oracle.pytools/enhanced_reporting.py
source: repo docs (build sync)Edit this page on GitHub →