Plectis
This page

Paper module

Agentic Vulnerability Discovery Patch-Proof Replay

The agentic vulnerability discovery patch-proof replay validates metadata-only synthetic vulnerability evidence chains before any found-and-fixed security language is allowed.

Contains 23 sections · 1 diagram · 6 references

The write-up

Patch-proof language needs more than a claim

"Found and fixed a security bug" is easy to type and hard to check, standing equally for a tested repair, a patch never run, a false positive, or an empty benchmark number. An agent that says it "found and fixed a security bug" is making a claim that is easy to type and hard to check. The phrase can stand for a real, tested repair. It can also stand for a patch that was never run, a false positive promoted to a finding, or a benchmark number with nothing behind it.

Seven evidence stages must agree

It breaks the claim into a synthetic evidence chain, from target through issue, trace, patch, test, witness, and verifier record, and checks the pieces line up before allowing patch-proof language. This component takes that claim apart into an inspectable chain of synthetic evidence and checks that the pieces line up before any patch-proof language is allowed. The chain runs from a made-up target, through a suspected issue, a trace that backs it, an abstract exploitability reference, a patch, a regression test, an executable witness, and a verifier record. Nothing in the chain is a real target, exploit, payload, or account secret. The result record says whether the declared chain holds together, and carries no attack material.

Synthetic replay grants no security authority

It is a synthetic, metadata-only replay, not live security work, that runs against no real system, judges no bug or fix as genuine, and produces no benchmark claims. The code lives in src/microcosm_core/organs/agentic_vulnerability_discovery_patch_proof_replay.py. It is a synthetic, metadata-only replay, not live security work. It does not run against real systems, does not judge whether the bug or fix is genuine, and does not produce a benchmark claims.

Purpose

Why two recompute checks exist

A summary can hide the absence of the work it summarises, so instead of trusting the fixture's labels two checks recompute the thing the fixture claims. The problem is that "found and fixed" is a summary, and a summary can hide the absence of the work it summarises. A loose check that only reads the fixture's own labels would pass a chain that asserts a green result without the work behind it. Two checks here refuse that by recomputing the thing the fixture claims, rather than trusting the field.

Recompute one: running the regression witnesses

The first recompute runs each witness's mini-target twice, unpatched and patched, and rejects any witness whose declared pre and post outputs do not match the computed ones. The first recompute is on the executable regression witnesses. Each witness names one of three small public mini-targets: a webhook redirect allowlist, a notebook log redactor, and a scheduler path normaliser. The validator runs that function twice, once unpatched and once patched, and compares its own computed outputs against the expected_pre_patch and expected_post_patch values the fixture declared. A witness whose declared output does not match the computed output is rejected.

Recompute two: the verifier verdict

The second recompute derives each verifier verdict from the joined hypothesis, proof, patch, test, and witness evidence, and requires the filename to match rather than trusting the record's own label. The second recompute is on the verifier records. Each record's pass or false_positive verdict is recomputed from the joined hypothesis, proof, patch, test, and witness evidence, and the record's filename must match that recomputed verdict. The record's own label is not taken on trust.

How it works

_build_result orchestrates the validators

_build_result loads inputs and policy, scans every path for secrets, builds the public trace, then runs one validator per evidence kind, passing only when every check and negative case clears. _build_result is the orchestrator. It loads the fixture inputs, loads the forbidden-class policy, runs a secret-exclusion scan over every input path, builds the public agent-execution trace, then runs one validator per evidence kind in dependency order. Each validator returns a status, exported rows, and a list of findings. A result reaches pass only when there are no missing negative cases, the secret scan has zero blocking hits, the public trace status is pass, every positive validator returned pass, and, for the exported bundle, the source-module manifest returned pass.

Each validator joins against the preceding stage

The validators form an ordered evidence join in which every stage resolves its rows against the stage immediately before it. The validators form a join, not a scanner. Each stage resolves its rows against the stage before it.

FunctionRole
runFixture entry point. Runs _build_result with negative cases on.
run_patch_proof_bundleExported-bundle entry point. Negative cases off, source-module manifest required.
_build_resultLoads inputs, runs every validator, computes the final status.
validate_issue_hypothesesEach hypothesis joins to a synthetic target and cites evidence refs; needs at least four rows.
validate_trace_evidenceEach trace joins to a hypothesis; the set must cover static, dynamic, and property types.
validate_patch_diffsEach patch-required hypothesis carries a metadata-only diff, updates tests, and claims no source-file changes.
validate_regression_testsEach patch pairs with a test that fails before the patch and passes after it.
validate_executable_regression_witnessesRuns the mini-target twice and compares computed output to the declared pre/post values.
validate_verifier_receiptsRecomputes each pass or false_positive verdict from joined evidence and checks the filename.
validate_sandbox_policy_verdictsEach verdict precedes action and denies live-target and network material.
validate_cold_replayEach replay row reproduces its trace, patch record, and sandbox verdict.
validate_negative_casesRecords the forbidden overclaims the fixture is expected to trip.
_source_module_manifest_resultDigest-checks the copied public source bodies carried by the exported bundle.

Three mini-target engines run both ways

Three MINI_TARGETS engines each take a patched flag: unpatched they leak or over-allow, patched they close the hole, and running both forms confirms a declared fails-before-passes-after test. The three mini-target engines are _webhook_redirect_allowlist, _notebook_log_redaction, and _scheduler_path_normalization, registered in MINI_TARGETS. Each takes an input and a patched flag. Unpatched, the webhook engine allows any redirect, the notebook engine leaks its sensitive refs, and the scheduler engine accepts a path that escapes the workspace. Patched, each closes its hole. Running both forms is what lets validate_executable_regression_witnesses confirm that a declared "fails before, passes after" test actually does.

Strict join order blocks broken chains

The join is strict: an unresolved hypothesis, a patch missing its proof or diff, a patch with no test, or a promoted false positive is each blocked. The join order is strict. A hypothesis that does not resolve to a synthetic target is blocked. A patch-required hypothesis missing either an exploitability proof or a metadata-only patch diff is blocked. A patch with no paired regression test is blocked. A false positive promoted to a finding is blocked, because validate_verifier_receipts will not recompute its verdict as pass.

Diagram of the mechanism (9 steps).
synthetic targetssynthetic targetsissue hypothesesissue hypothesestrace evidencetrace evidenceexploitability proofsexploitability proofspatch diffspatch diffsregression testsregression testsexecutable witnessesrun mini-target twiceexecutable witnesses run mini-target twiceverifier recordsrecompute verdictverifier records recompute verdictresult statusresult status
Diagram source & refs
flowchart TD targets["synthetic targets"] hypotheses["issue hypotheses"] traces["trace evidence"] proofs["exploitability proofs"] patches["patch diffs"] tests["regression tests"] witnesses["executable witnesses run mini-target twice"] verifiers["verifier records recompute verdict"] status["result status"] targets --> hypotheses hypotheses --> traces hypotheses --> proofs hypotheses --> patches patches --> tests tests --> witnesses witnesses --> verifiers verifiers --> status

Two runtime modes, both metadata-only

run drives the fixture with negative cases on, run_patch_proof_bundle drives the exported bundle as the public example, and both write metadata-only records with source bodies kept behind manifest hashes. The runtime keeps two modes separate. run drives the first-wave fixture with negative cases on, so it must observe every expected overclaim failure. run_patch_proof_bundle drives the exported bundle as the public runtime example, so its expected negative cases can be empty while it still proves the source-body floor, the public trace, the digest checks, and the regression witnesses. Both write metadata-only result records. Copied source bodies stay behind source_module_manifest.json refs and hashes; the exported bundle carries nine digest-verified public source bodies.

Negative cases

Eight overclaims the runtime must trip

Eight EXPECTED_NEGATIVE_CASES overclaims must each trip a matching error code or the run is blocked, and _has_forbidden_key separately rejects any row carrying a forbidden field. The first-wave fixture includes eight negative cases, held in EXPECTED_NEGATIVE_CASES. Each one is an overclaim the runtime must trip, not a capability it offers: live_target_material, real_cve_exploitation, weaponized_payload_export, account secret material, network_exfiltration, exploit_instruction_steps, patch_without_tests, and benchmark_score_claim. validate_negative_cases records the matching error code for each, for example AGENTIC_VULN_PATCH_WITHOUT_TESTS when a patch claim arrives with no regression test. If any expected case goes unobserved, the run is blocked. Separately, _has_forbidden_key rejects any row that carries a forbidden field such as a raw exploit payload, a account secret value, or a live target URL.

Prior Art Grounding

Test-backed repair lineage from SWE-bench

The design borrows the accountability pattern of SWE-bench, SWE-agent, and security benchmarks like CyberSecEval 2 and SecCodePLT, requiring evidence to line up before patch-proof language, without importing live exploits. This component borrows an accountability pattern from agentic software-engineering and security-evaluation work that treats a code repair as an executable, test-backed claim rather than a prose claim. SWE-bench framed repository issue resolution as a task with real codebases and test-based patch evaluation, and SWE-agent made the agent-computer interface part of the repair loop. Security benchmarks such as CyberSecEval 2 and SecCodePLT motivate separating a secure-code or vulnerability claim from an uninspected generated patch. The borrowed idea is narrow: hypotheses, traces, patches, tests, and verifier records must line up before patch-proof language is allowed. It does not import live targets, CVE exploitation, weaponized payloads, or benchmark claims.

Validation Result record Path

Fixture output stays outside the system tree

The first-wave validator runs from the system root and writes its result record to a disposable path outside the working tree. Run the first-wave fixture validator from the system root and write its record outside the working tree:

Then run the exported bundle validator:

cd microcosm-substrate && PYTHONPATH=src ../repo-python -m microcosm_core.organs.agentic_vulnerability_discovery_patch_proof_replay \
  run-patch-proof-bundle \
  --input examples/agentic_vulnerability_discovery_patch_proof_replay/exported_patch_proof_bundle \
  --out /tmp/agentic_vulnerability_patch_proof_bundle_receipt \
  --card > /tmp/agentic_vulnerability_patch_proof_bundle_card.json

The focused regression test is:

PYTHONPATH=src ./repo-pytest \
  tests/test_agentic_vulnerability_discovery_patch_proof_replay.py

What a pass and the rejection tests prove

A pass means the whole join held with both recompute checks agreeing, a clean scan, and every negative case tripped, while rejection tests mutate the chain and require a blocked result. A pass means the whole join held: the synthetic chain resolved end to end, both recompute checks agreed with the fixture, the secret scan was clean, and every expected negative case tripped. The rejection tests in the same file mutate the chain, remove a regression test, tamper a witness, cross-wire a verifier record, or alter a source-module digest, and require a blocked result with a specific error code.

Scope boundary

Scope limit

The strongest supported claim

On the public fixtures the synthetic chain resolves and both recompute checks pass, with witnesses, verifier verdicts, and paired tests all agreeing and every forbidden overclaim observed. The strongest claim this component supports is narrow. On the public fixtures, the synthetic evidence chain resolves and both recompute checks pass: witnesses match their computed pre/post outputs, verifier verdicts match their recomputed result, patches pair with real tests, and every forbidden overclaim is observed. That is the scope limit, and it is where the scope limit sits.

What the component refuses beyond that

It refuses everything past that: no live targets, real CVE exploitation, weaponized payloads, account secrets, external model access, source-file changes, benchmark claims, or whole-system security claim, only the local synthetic records. It refuses everything past that. It does not test live targets, perform real CVE exploitation, export weaponized payloads, handle account secrets, authorise network exfiltration, or emit actionable exploit instructions. It does not make external model access, change source files, claim a benchmark security score, or judge patch correctness on a real repository. It is not launch or publishing-scope decision, and it is not a whole-system security claim. The proof boundary is the local result records, the synthetic bundle, the digest-checked source-module manifest, and the named negative cases, nothing wider.

Context & evidence

In short Agentic Vulnerability Discovery Patch-Proof Replay is the public security-claim boundary for Microcosm. It checks projection protocol, vulnerability policy, synthetic target refs, issue hypotheses, trace evidence, abstract exploitability refs, patch diff refs, regression tests, verifier result records, sandbox verdicts, false-positive triage, cold replay, public agent-execution trace spans, secret-exclusion scan, nine copied source/control/standard/tool bodies, source-module manifest digests, metadata-only result record policy, and eight security-overclaim negative cases while keeping live targets, real CVE exploitation, weaponized payloads, account secrets, network exfiltration steps, actionable exploit instructions, model-output data, raw issue or patch bodies, benchmark claims, and source-file changes out of result records.

Scope limit Copied public source/control/standard/tool bodies, metadata-only synthetic patch-proof replay result records, public agent-execution trace spans, and fixture validation only; no live target testing, real CVE exploitation, weaponized payload export, account secret handling, network exfiltration, actionable exploit instructions, external model access, source-file changes, benchmark security score, launch-scope decision, publishing-scope decision, whole-system security claim, or product-progress evidence.

Source

Source Source module: src/microcosm_core/organs/agentic_vulnerability_discovery_patch_proof_replay.py · Design note · Source registry