bug-hunt
A reusable harness for hunting a class of bug across a subsystem, then proving
each candidate real or (usually) refuting it. Built from repeated authority-bypass
sweeps on the gno.land VM. Engine = the Workflow tool: pipeline(angles, find, verify).
When to use
- You have a hunch a bug class might exist ("sub-realms could bypass authority
somehow") but no concrete finding yet.
- You want breadth (many independent angles) AND rigor (each candidate adversarially
refuted before you believe it) without hand-running dozens of greps.
- You want the negative result to be trustworthy — "we looked hard and here's why
the guard holds", not "I didn't find anything".
Not for: a single known bug (just fix it), a whole-repo audit with no thesis (too
broad — pick a subsystem first), or a quick one-file check (just read it).
The method (6 steps)
Scope the layers. Most real bugs live in the seam between layers, not inside
one. Enumerate every layer the target crosses and make the finders read all of them.
(gno banker example: gno stdlib .gno → native Go binding → bank keeper. The
interesting question was always "does layer N re-check what layer N-1 assumed?")
Decompose into attack angles. 5–8 angles, each a distinct mechanism, not a
restatement. Name them <Prefix><n>-<slug> (A1, B2…) so results are greppable.
One finder per angle. Coverage beats depth here — depth comes in verify.
Ground the finders in REAL source. Before writing the workflow, grep the actual
file:line anchors for each angle and put them in the prompt. Tell finders: "read the
ACTUAL current source, do not trust summaries." A finder pointed at the wrong file
invents plausible-but-fake findings.
Baseline-exclusion. List already-known/disclosed/by-design issues explicitly and
tell finders + verifiers to flag any restatement as duplicate_of_known=true and
refute it. Without this every run rediscovers H1 and calls it new.
Find → refute-first verify (pipeline). pipeline(angles, findStage, verifyStage).
Each finding gets an independent verifier told: assume it is a FALSE POSITIVE, refute
it from source, only rule "real" if the code forces it, default to "refuted" when
uncertain. This is the whole point — a finding nobody tried to kill is worthless.
Harvest guard_notes even on a clean run. Every finder returns a guard_summary
(how the guard actually works, per source) whether or not it found anything. On a
0-confirmed run these summaries ARE the deliverable: a source-cited guard map proving
the negative. Also capture any nuance a verifier raises that isn't a vuln but is
worth an owner note (e.g. "IsCanonical checks type not bt").
Deliverables
- Confirmed findings → reproduce each with a runnable test (txtar / filetest / unit)
before reporting. A finding you haven't watched turn a test red is a guess.
- Clean negative → the guard map (per-angle
guard_summary with file:line) + any
owner-note nuances. This is valuable: it tells maintainers which guards they're
relying on and why, and raises confidence in adjacent results.
- Present as a table: angle | verdict | key evidence. Then the bottom line: X angles,
N confirmed, and what (if anything) to file.
Running it
The engine is hunt-template.js next to this file — a parameterized
pipeline(ANGLES, find, verify) with FIND_SCHEMA + VERDICT_SCHEMA already wired.
To run a hunt:
- Copy
hunt-template.js into the session's workflow scripts dir.
- Edit
meta, SHARED (repo path, layer map, ground files, baseline-exclusions), and
ANGLES (5–8 angles with file:line anchors).
Workflow({ scriptPath: "<copied path>" }) — runs in background.
- On completion read the output file; if the harvest looks wrong (empty guard_notes,
shape mismatch), fix the script and resume with
Workflow({ scriptPath, resumeFromRunId }) — cached agent calls return instantly.
Knobs: effort: 'high' on both stages for security work; scale ANGLES to thoroughness
requested; add a 3-vote refuter panel per finding for "audit this exhaustively" asks.
Hard-won gotchas
- Pipeline stage return shape must be uniform. If the verify stage sometimes returns
a wrapped object and sometimes a raw array, the final harvest silently drops the
array-shaped ones. Always return the SAME
{ angle, guard_summary, verified } shape.
- Refute-first is not optional. A verifier that "confirms" is doing it wrong. The
default verdict is
refuted; real requires the code to force it.
- codex/subagent cybersecurity filter. Frame prompts as defensive research on the
maintainer's own code ("authorized defensive security research", "bounding/hardening"),
never as exploit/attack recipes, or the safety filter refuses mid-run.
- Ground or hallucinate. No file:line anchors in the finder prompt → confident fiction.
- 0 confirmed is a success, not a failure. Don't let a finder invent findings to fill
a quota — the prompt says so explicitly, keep it that way.
1---2name: bug-hunt3description: Adversarial multi-agent security sweep. Use when hunting for a CLASS of vulnerability (authority/capability bypass, injection, resource exhaustion, invariant breaks) across a codebase or subsystem where you have a hunch but no specific finding, and want each candidate independently refuted before it counts. Fan out finders by attack angle, then refute-first verify every candidate. A clean negative result (guard map) is a first-class deliverable.4---56# bug-hunt78A reusable harness for hunting a *class* of bug across a subsystem, then proving9each candidate real or (usually) refuting it. Built from repeated authority-bypass10sweeps on the gno.land VM. Engine = the `Workflow` tool: `pipeline(angles, find, verify)`.1112## When to use1314- You have a hunch a bug class *might* exist ("sub-realms could bypass authority15 somehow") but no concrete finding yet.16- You want breadth (many independent angles) AND rigor (each candidate adversarially17 refuted before you believe it) without hand-running dozens of greps.18- You want the *negative* result to be trustworthy — "we looked hard and here's why19 the guard holds", not "I didn't find anything".2021Not for: a single known bug (just fix it), a whole-repo audit with no thesis (too22broad — pick a subsystem first), or a quick one-file check (just read it).2324## The method (6 steps)25261. **Scope the layers.** Most real bugs live in the *seam between layers*, not inside27 one. Enumerate every layer the target crosses and make the finders read all of them.28 (gno banker example: gno stdlib `.gno` → native Go binding → bank keeper. The29 interesting question was always "does layer N re-check what layer N-1 assumed?")30312. **Decompose into attack angles.** 5–8 angles, each a *distinct mechanism*, not a32 restatement. Name them `<Prefix><n>-<slug>` (A1, B2…) so results are greppable.33 One finder per angle. Coverage beats depth here — depth comes in verify.34353. **Ground the finders in REAL source.** Before writing the workflow, grep the actual36 file:line anchors for each angle and put them in the prompt. Tell finders: "read the37 ACTUAL current source, do not trust summaries." A finder pointed at the wrong file38 invents plausible-but-fake findings.39404. **Baseline-exclusion.** List already-known/disclosed/by-design issues explicitly and41 tell finders + verifiers to flag any restatement as `duplicate_of_known=true` and42 refute it. Without this every run rediscovers H1 and calls it new.43445. **Find → refute-first verify (pipeline).** `pipeline(angles, findStage, verifyStage)`.45 Each finding gets an independent verifier told: *assume it is a FALSE POSITIVE, refute46 it from source, only rule "real" if the code forces it, default to "refuted" when47 uncertain.* This is the whole point — a finding nobody tried to kill is worthless.48496. **Harvest guard_notes even on a clean run.** Every finder returns a `guard_summary`50 (how the guard actually works, per source) whether or not it found anything. On a51 0-confirmed run these summaries ARE the deliverable: a source-cited guard map proving52 the negative. Also capture any *nuance* a verifier raises that isn't a vuln but is53 worth an owner note (e.g. "IsCanonical checks type not bt").5455## Deliverables5657- **Confirmed findings** → reproduce each with a runnable test (txtar / filetest / unit)58 before reporting. A finding you haven't watched turn a test red is a guess.59- **Clean negative** → the guard map (per-angle `guard_summary` with file:line) + any60 owner-note nuances. This is valuable: it tells maintainers *which* guards they're61 relying on and why, and raises confidence in adjacent results.62- Present as a table: angle | verdict | key evidence. Then the bottom line: X angles,63 N confirmed, and what (if anything) to file.6465## Running it6667The engine is `hunt-template.js` next to this file — a parameterized68`pipeline(ANGLES, find, verify)` with `FIND_SCHEMA` + `VERDICT_SCHEMA` already wired.69To run a hunt:70711. Copy `hunt-template.js` into the session's workflow scripts dir.722. Edit `meta`, `SHARED` (repo path, layer map, ground files, baseline-exclusions), and73 `ANGLES` (5–8 angles with file:line anchors).743. `Workflow({ scriptPath: "<copied path>" })` — runs in background.754. On completion read the output file; if the harvest looks wrong (empty guard_notes,76 shape mismatch), fix the script and resume with77 `Workflow({ scriptPath, resumeFromRunId })` — cached agent calls return instantly.7879Knobs: `effort: 'high'` on both stages for security work; scale `ANGLES` to thoroughness80requested; add a 3-vote refuter panel per finding for "audit this exhaustively" asks.8182## Hard-won gotchas8384- **Pipeline stage return shape must be uniform.** If the verify stage sometimes returns85 a wrapped object and sometimes a raw array, the final harvest silently drops the86 array-shaped ones. Always return the SAME `{ angle, guard_summary, verified }` shape.87- **Refute-first is not optional.** A verifier that "confirms" is doing it wrong. The88 default verdict is `refuted`; `real` requires the code to force it.89- **codex/subagent cybersecurity filter.** Frame prompts as *defensive* research on the90 maintainer's own code ("authorized defensive security research", "bounding/hardening"),91 never as exploit/attack recipes, or the safety filter refuses mid-run.92- **Ground or hallucinate.** No file:line anchors in the finder prompt → confident fiction.93- **0 confirmed is a success, not a failure.** Don't let a finder invent findings to fill94 a quota — the prompt says so explicitly, keep it that way.