@xaccefy/pi-casefile 0.8.3 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -5
- package/package.json +13 -4
- package/skills/casefile/SKILL.md +4 -3
- package/src/evidence.ts +501 -0
- package/src/harness-verify.ts +693 -0
- package/src/index.ts +391 -224
- package/src/ledger-worker-entry.ts +35 -0
- package/src/ledger-worker.ts +77 -0
- package/src/ledger.ts +853 -233
- package/src/pipeline-submit.ts +153 -43
- package/src/poc-runner.ts +216 -65
- package/src/safe-state.ts +108 -0
- package/src/scratchpad.ts +67 -28
- package/src/workflow.ts +91 -23
package/src/workflow.ts
CHANGED
|
@@ -25,28 +25,86 @@ RECON -> HYPOTHESIS --+
|
|
|
25
25
|
|
|
|
26
26
|
+--> KILLED (insufficient impact, duplicate, etc.)
|
|
27
27
|
\`\`\``;
|
|
28
|
-
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Subagent-dispatch conventions per host. Pi (pi-subagents extension) dispatches
|
|
31
|
+
* through \`subagent({ workflowScript: runs.run(...) })\`; OMP (fork, @oh-my-pi)
|
|
32
|
+
* dispatches through its native \`task\` tool with a tasks array. The workflow
|
|
33
|
+
* body is identical — only the launch mechanics differ.
|
|
34
|
+
*/
|
|
35
|
+
type DispatchSpec = {
|
|
36
|
+
/** Tool-reference paragraph. */
|
|
37
|
+
reference: string;
|
|
38
|
+
/** HARD GATE launch sentence (after "record the entry-point inventory, then STOP..."). */
|
|
39
|
+
hardGate: string;
|
|
40
|
+
/** Crash-handling paragraph. */
|
|
41
|
+
crash: string;
|
|
42
|
+
/** Skeptic dispatch snippet (follows "dispatch it BEFORE the exploit agent with "). */
|
|
43
|
+
skeptic: string;
|
|
44
|
+
/** Reporter dispatch snippet (follows "Dispatch the reporter subagent with "). */
|
|
45
|
+
reporter: string;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const PI_DISPATCH: DispatchSpec = {
|
|
49
|
+
reference:
|
|
50
|
+
"**Subagent dispatch:** every launch uses `subagent({ workflowScript: \"return runs.run('stable-key', { agent: 'tracer', task: '...' })\", context: 'fresh', async: true })`. Parallel HUNT uses one workflowScript with `return runs.all([{ key: 'run-class-attempt', agent: 'auditor', task: '...' }, ...])`. Stable keys include run, stage, class/case, and attempt. Dispatch specialists; do NOT do their work yourself.",
|
|
51
|
+
hardGate:
|
|
52
|
+
"Your next tool call MUST launch one async workflowScript whose `runs.all([...])` dispatches HUNT auditors.",
|
|
53
|
+
crash:
|
|
54
|
+
"**Subagent crash handling:** a crash (SIGABRT, OOM, timeout) is a RETRY, not a verdict. Launch one new workflowScript with the same specialist task, a new stable attempt key, and a stronger model. Crash again → record `blocked: <agent> crashed` in the pipeline-run case and continue; never silently drop the stage.",
|
|
55
|
+
skeptic:
|
|
56
|
+
"`subagent({ workflowScript: \"return runs.run('skeptic-<case>-1', { agent: 'skeptic', task: '...' })\", context: 'fresh', async: true })`",
|
|
57
|
+
reporter:
|
|
58
|
+
"`subagent({ workflowScript: \"return runs.run('report-<case>-1', { agent: 'reporter', task: 'Write the final report. case_id=<id>, context_path=<context path>, report_path=<report path>, program_name=<if known>.' })\", context: 'fresh', async: true })`",
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const OMP_DISPATCH: DispatchSpec = {
|
|
62
|
+
reference:
|
|
63
|
+
"**Subagent dispatch (OMP):** every launch uses `task({ context: 'fresh', tasks: [{ name: 'stable-key', agent: 'tracer', task: '...' }] })`. Parallel HUNT dispatches ONE task call whose `tasks` array carries one entry per attack class: `task({ context: 'fresh', tasks: [{ name: 'hunt-sqli-1', agent: 'auditor', task: '...' }, { name: 'hunt-xss-1', agent: 'auditor', task: '...' }] })`. Stable names include run, stage, class/case, and attempt. Results deliver automatically; steer with `hub`. Dispatch specialists; do NOT do their work yourself.",
|
|
64
|
+
hardGate:
|
|
65
|
+
"Your next tool call MUST launch one async `task` call whose `tasks` array dispatches HUNT auditors (one entry per attack class). When their results are delivered, submit each output through PipelineSubmit.",
|
|
66
|
+
crash:
|
|
67
|
+
"**Subagent crash handling:** a failed or hung task (SIGABRT, OOM, timeout) is a RETRY, not a verdict. Re-dispatch the same specialist task with a new attempt name and a stronger model. Crash again → record `blocked: <agent> crashed` in the pipeline-run case and continue; never silently drop the stage.",
|
|
68
|
+
skeptic:
|
|
69
|
+
"`task({ context: 'fresh', tasks: [{ name: 'skeptic-<case>-1', agent: 'skeptic', task: '...' }] })`",
|
|
70
|
+
reporter:
|
|
71
|
+
"`task({ context: 'fresh', tasks: [{ name: 'report-<case>-1', agent: 'reporter', task: 'Write the final report. case_id=<id>, context_path=<context path>, report_path=<report path>, program_name=<if known>.' }] })`",
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/** Build the full cyber workflow for a host's dispatch convention. */
|
|
75
|
+
function buildCyberWorkflow(d: DispatchSpec): string {
|
|
76
|
+
return `
|
|
29
77
|
# Cyber Workflow (Attacker-Oriented)
|
|
30
78
|
|
|
31
79
|
Think like a real external attacker, not a code reviewer. Technical bugs are cheap; **reachable attacker impact** is what matters. Every lead starts HYPOTHESIS; nothing reaches CONFIRMED without a proven attacker path and demonstrated impact against a real production target or faithful replica.
|
|
32
80
|
|
|
33
81
|
## Tool Reference
|
|
34
82
|
|
|
35
|
-
**Casefile (state tracking):** CaseAdd, CaseUpdate, CaseGet, CaseList, CaseSearch, CaseLink, CaseUnlink, CaseContext, PromoteFinding, PipelineSubmit
|
|
83
|
+
**Casefile (state tracking):** CaseAdd, CaseUpdate, CaseGet, CaseList, CaseSearch, CaseLink, CaseUnlink, CaseContext, PromoteFinding, ConfirmFinding, PipelineSubmit
|
|
36
84
|
|
|
37
85
|
**Scratchpad (pipeline artifacts):** ScratchpadInit, ScratchpadResume, ScratchpadCheckpoint, ScratchpadWrite, ScratchpadRead, ScratchpadPhaseDone, ScratchpadClear
|
|
38
86
|
|
|
39
87
|
**Web lookup (research):** web_search, web_fetch, exploit_search, context7, deepwiki, http_request
|
|
40
88
|
|
|
41
|
-
|
|
89
|
+
${d.reference}
|
|
42
90
|
|
|
43
91
|
## Stage Machine (run in order — you are the coordinator)
|
|
44
92
|
|
|
45
93
|
RECON (you, inline) → **HUNT** (auditor subagents, one per attack class, parallel) → TRACE (tracer) → SKEPTIC (high-confidence only) → VALIDATE (exploit) → CHAIN (chain) → REPORT (reporter)
|
|
46
94
|
|
|
47
|
-
|
|
95
|
+
### Blackbox doctrine — gather everything first (no source access)
|
|
96
|
+
|
|
97
|
+
Live web target, CTF, or bounty box: the target is opaque and **every later stage's yield is capped by what RECON learned** — shallow recon makes every later NOT_FOUND a guess. The primary goal of RECON in blackbox mode is not to find one bug; it is to gather the MAXIMUM intel about the target/challenge and turn the black box into a map you keep referring back to. Before any exploitation, harvest all observable intel:
|
|
98
|
+
- **Client-side code is a gift** — pull every JS bundle and, when present, its **source map** (\`.js.map\`): it reconstructs the original tree — routes, API/WS endpoints, feature flags, internal hostnames, and hardcoded secrets/keys. One recovered source map beats a week of blind fuzzing.
|
|
99
|
+
- **Zero-traffic intel first** — \`robots.txt\`, \`sitemap.xml\`, \`/.well-known/\`, OpenAPI/Swagger, GraphQL introspection, \`/.git\` · \`/.env\` · backups, and passive archives (Wayback/\`gau\`).
|
|
100
|
+
- **Fingerprint precisely** — stack + exact versions → \`exploit_search\` for CVEs; every header, cookie name, and error page is a signal.
|
|
101
|
+
- **Bank it** — write the map to the scratchpad and file high-value leaks (source map, origin IP, exposed schema, leaked creds) as \`EvidenceAdd role=observation\`; they are leads to pivot to directly, not trivia. Tactical commands: web-pentest skill §2.
|
|
102
|
+
|
|
103
|
+
**Observe behavior, then analyze — static intel is only half.** Interrogate the target empirically and infer its internals from how it *reacts*; the differential (vary one input, watch what changes) is the signal. **Web/API:** status vs length vs timing vs body vs error across crafted inputs; how auth actually gates (401 vs 302 vs 200-with-error); reflected vs stored; timing oracles for blind bugs; state changes across a request sequence. **Binary/local target:** map the I/O contract, trace syscalls + library calls (\`strace\`/\`ltrace\`), feed malformed/boundary input and watch crashes, signals, and return codes, and diff behavior across inputs to expose the parse/branch logic. **Protocol/service:** walk the handshake + state machine, then replay and mutate one field and observe the divergence and side effects. Loop: stimulus → observe → infer the internal model → craft a discriminating probe → repeat. Every observed anomaly (crash, error leak, timing gap, unexpected 200, state change) is a HYPOTHESIS — \`CaseAdd\` it with its \`disproveIf\`, don't just note it.
|
|
48
104
|
|
|
49
|
-
**
|
|
105
|
+
**HARD GATE — after RECON:** record the entry-point inventory, then STOP all inline reading/probing. ${d.hardGate} When its completion is delivered, submit each output through PipelineSubmit. If you catch yourself mapping a sink, reading a handler, or probing an endpoint beyond the recon inventory, stop and add it to a HUNT task.
|
|
106
|
+
|
|
107
|
+
${d.crash}
|
|
50
108
|
|
|
51
109
|
## Case Lifecycle (State Machine)
|
|
52
110
|
${LIFECYCLE_DIAGRAM}
|
|
@@ -57,8 +115,9 @@ ${LIFECYCLE_DIAGRAM}
|
|
|
57
115
|
|-------|-----------|-------------|
|
|
58
116
|
| RECON | (none) | Map attack surface, fingerprint, search CVEs. Something interesting → HYPOTHESIS. |
|
|
59
117
|
| HUNT | HYPOTHESIS | Document the lead (impact not required yet). Clear intended-behavior/artifact → KILLED; else INVESTIGATING. |
|
|
60
|
-
|
|
|
61
|
-
|
|
|
118
|
+
| TRACE / SKEPTIC / VALIDATE | INVESTIGATING | Trace reachability, attempt disconfirmation, and produce the pending PoC evidence bundle. Failure stays INVESTIGATING or becomes KILLED. |
|
|
119
|
+
| MAIN REVIEW | CONFIRMED | The main agent judges whether the machine differential actually establishes the vulnerability and impact, then commits through ConfirmFinding. |
|
|
120
|
+
| CHAIN | CONFIRMED | Link confirmed findings and evaluate multi-step exploit paths; this stage does not confirm new cases. |
|
|
62
121
|
| REPORT | REPORTED | CaseContext → reporter agent → report-readiness gate. |
|
|
63
122
|
|
|
64
123
|
### Preconditions Per State Transition (MANDATORY)
|
|
@@ -66,7 +125,7 @@ ${LIFECYCLE_DIAGRAM}
|
|
|
66
125
|
| Advance To | Required Case Fields | On Disk |
|
|
67
126
|
|-----------|---------------------|---------|
|
|
68
127
|
| HYPOTHESIS → INVESTIGATING | evidence (observations), confidence | Notes on what was observed |
|
|
69
|
-
| INVESTIGATING → **CONFIRMED** | evidence, poc, **impact** (content below), severity, **target**, **disconfirmation** (
|
|
128
|
+
| INVESTIGATING → **CONFIRMED** | evidence, poc, **impact** (content below), severity, **target**, **disconfirmation** (the main agent's documented disprove attempt) | PromoteFinding phase 1: PoC runs 2× against target + 1× against an operator-approved \`control_target\` (same script, sha256-enforced); every run completes at exit zero with output fully captured and writes nonce-bound \`evidence.json\` with a response-body predicate; the harness obtains conclusive target/control responses and requires \`target_only\`. Then the **main/coordinator agent itself** reviews and calls **ConfirmFinding**, which captures a fresh second harness replay before commit. Worker agents cannot submit phase 2. Zero exit is necessary run integrity, never vulnerability proof; output markers are diagnostic only. |
|
|
70
129
|
| Any → KILLED | assumptions (why it died) | — |
|
|
71
130
|
| CONFIRMED → REPORTED | CaseContext(id) succeeded (records report path) AND the reporter agent wrote the report file | Context bundle + report file |
|
|
72
131
|
|
|
@@ -120,22 +179,24 @@ If you cannot name a concrete attacker who gains something they should not have
|
|
|
120
179
|
|
|
121
180
|
The finding must survive an attempt to disprove it. Two tiers, gated on \`confidence\` (severity comes later, from the PoC):
|
|
122
181
|
|
|
123
|
-
**\`confidence: high\` → skeptic subagent (MANDATORY):** dispatch it BEFORE the exploit agent with
|
|
182
|
+
**\`confidence: high\` → skeptic subagent (MANDATORY):** dispatch it BEFORE the exploit agent with ${d.skeptic}. It independently re-reads the source (or re-probes live), verifies scope, tries to disprove, and audits the PoC file for cheats. Its schema-validated verdict must carry its own \`disconfirmation_attempt\` (CONFIRMED verdicts without one are rejected by PipelineSubmit). DISPROVEN → add EvidenceAdd role=refutation, then killed directly, no tie-breaker. Do NOT skip; do NOT self-disconfirm high-confidence findings.
|
|
124
183
|
|
|
125
|
-
**Below high → self-disconfirmation:** actively try to disprove your own finding; document it. Not a formality.
|
|
184
|
+
**Below high → self-disconfirmation:** actively try to disprove your own finding; document it (see the strong/weak example below). Not a formality.
|
|
126
185
|
|
|
127
186
|
An attempt: reproduce under different conditions (auth/config/network position); test the behavior against docs/baseline endpoints; trigger protections (WAF/CSP/CSRF/rate limits); try to trigger the same behavior without your attacker-controlled input. Document in \`disconfirmation\`: what you tried, how (conditions/inputs/target), result (failing to disprove is the expected outcome), why the attempt was valid.
|
|
128
187
|
|
|
129
188
|
Strong example: "Read /api/users/123 as user B after confirming user A owns 123 → 403. Repeated with X-Override-User header (seen in admin traffic) → user A's data returned. Protection bypassed via the admin header."
|
|
130
189
|
Weak: "Tried to disprove. Could not." — insufficient.
|
|
131
190
|
|
|
132
|
-
|
|
191
|
+
**The CONFIRMED disconfirmation comes from the main agent, not a script or worker.** There is no \`disconfirmation_path\` gate: after PromoteFinding, the main/coordinator must write its own failed disproof attempt, which becomes the case's \`disconfirmation\`, and call ConfirmFinding to capture the fresh phase-2 replay. A worker/subagent cannot call ConfirmFinding, and a verdict without the main agent's \`disconfirmation_attempt\` is rejected.
|
|
133
192
|
|
|
134
193
|
**Evidence chain closure (before PromoteFinding):** promotion is rejected unless the case carries an **artifact-backed** \`observation\` evidence item (EvidenceAdd role=observation with \`artifact_path\` — the initial signal, stored with its SHA-256) in addition to the auto-recorded reproduction item. Record observations as you go, not at promote time.
|
|
135
194
|
|
|
136
|
-
**
|
|
195
|
+
**PromoteFinding (phase 1) — evidence bundle, not markers.** Call it with \`poc_path\`, same-byte \`control_path\`, an operator-approved \`control_target\` from \`PI_POC_CONTROL_TARGETS\`, and \`local: true\` when the bug needs network. Every run must complete with fully captured output and write nonce-bound \`evidence.json\` whose \`expect\` includes \`body_contains\` or \`body_regex\`; status-only evidence is rejected. The harness pins DNS at connect time, keeps redirects on the bound host, sends the same request to target/control, and requires two conclusive responses with \`target_only\`. Private replay requires operator authorization. Blind/OOB classes fail closed until a source-separated oracle exists.
|
|
196
|
+
|
|
197
|
+
**ConfirmFinding (phase 2) — main-agent-only commit.** After PromoteFinding succeeds, do not dispatch confirmation. The main/coordinator agent must inspect the exact PoC/evidence, hunt trivial predicates/fabrication, attempt disconfirmation, and call \`ConfirmFinding(case_id, verdict)\` itself. A CONFIRMED call performs and stores a fresh harness-owned target/control replay; a caller-supplied re-execution checkbox is not accepted. CONFIRMED requires \`re_execution_note\`, \`differential: "target_only"\`, and the main agent's \`disconfirmation_attempt\`. Worker processes are rejected. **Never \`CaseUpdate(status: "confirmed")\` directly.**
|
|
137
198
|
|
|
138
|
-
**PoC audit (anti-cheat, before PromoteFinding):** have an independent eye on the PoC script itself. For \`confidence: high\` findings the skeptic agent re-reads the PoC file
|
|
199
|
+
**PoC audit (anti-cheat, before PromoteFinding):** have an independent eye on the PoC script itself. For \`confidence: high\` findings the skeptic agent re-reads the PoC file hunting unconditional success, trivial checks, constants, and local mocks. Record the audit as EvidenceAdd \`observation\` (or \`refutation\` if cheated). The main agent must re-read the exact script before ConfirmFinding; workers may challenge evidence but never decide promotion. Deterministic backstops are code: output completeness, nonce binding, response-body predicates, deterministic runs, operator-approved control, DNS-pinned conclusive replay, same-file sha256, and PoC byte-identity re-check at commit.
|
|
139
200
|
|
|
140
201
|
### 2. Design & Runtime Check — non-intentionality gate (mandatory)
|
|
141
202
|
|
|
@@ -180,14 +241,14 @@ Prove at least **one** real attacker-facing violation against a production-viabl
|
|
|
180
241
|
|
|
181
242
|
Impact text answers: *who is hurt, what is lost, how the attacker reaches it from production.* Theoretical impact, a second unproven bug, or unreachable-from-attacker → stay INVESTIGATING (chain it) or KILL.
|
|
182
243
|
|
|
183
|
-
**Severity is derived from PROVEN impact, not guessed** — set only after the
|
|
184
|
-
- **critical** = RCE, account takeover, or direct fund theft
|
|
244
|
+
**Severity is derived from PROVEN impact, not guessed** — set only after the machine differential and the main-agent review demonstrate the impact; a zero exit or PoC output alone is insufficient:
|
|
245
|
+
- **critical** = RCE, account takeover, or direct fund theft demonstrated in confirmed evidence
|
|
185
246
|
- **high** = sensitive data read/write, privilege escalation, SSRF to internal services
|
|
186
247
|
- **medium** = limited data exposure, XSS on sensitive page, IDOR on non-critical resources
|
|
187
248
|
- **low** = info leak, open redirect, self-only impact with a victim path
|
|
188
249
|
- **info** = best-practice gap, no demonstrated impact
|
|
189
250
|
|
|
190
|
-
"Could lead to"/"may allow"/"theoretically" = NOT proven — drop to what the
|
|
251
|
+
"Could lead to"/"may allow"/"theoretically" = NOT proven — drop to what the confirmed harness evidence shows. Under-claiming is safe; over-claiming gets rejected at triage.
|
|
191
252
|
|
|
192
253
|
### 7. Adversarial Self-Review
|
|
193
254
|
|
|
@@ -210,7 +271,7 @@ Reproduce at least twice or via two methods.
|
|
|
210
271
|
## At REPORT
|
|
211
272
|
|
|
212
273
|
1. **Run CaseContext(case_id)** — writes the context bundle (complete record, PoC + disconfirmation logs, links, pipeline artifacts) and records the report path.
|
|
213
|
-
2. **Dispatch the reporter subagent** with
|
|
274
|
+
2. **Dispatch the reporter subagent** with ${d.reporter}. It writes the polished report and flips the case to REPORTED.
|
|
214
275
|
3. **Report-readiness gate** (YOU check this on the reporter's output before accepting; on failure, re-dispatch with the gap list):
|
|
215
276
|
- Deterministic reproduction by another researcher
|
|
216
277
|
- Steps realistic in production
|
|
@@ -227,6 +288,13 @@ The ledger enforces a machine floor on the report file before accepting \`report
|
|
|
227
288
|
|
|
228
289
|
When a case is definitively dead (not "I don't know yet"), record the reason: ${KILL_REASONS_TEXT} (true bug, no realistic attacker value). Documenting kills prevents re-opening dead ends. Cases with unresolved unknowns stay INVESTIGATING, not killed.
|
|
229
290
|
`.trim();
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** Cyber workflow for Pi Agent (pi-subagents dispatch). */
|
|
294
|
+
export const STATIC_CYBER_WORKFLOW = buildCyberWorkflow(PI_DISPATCH);
|
|
295
|
+
|
|
296
|
+
/** Cyber workflow for OMP (fork of Pi; native `task` dispatch). */
|
|
297
|
+
export const STATIC_CYBER_WORKFLOW_OMP = buildCyberWorkflow(OMP_DISPATCH);
|
|
230
298
|
|
|
231
299
|
/**
|
|
232
300
|
* Cyber workflow for XP LITE mode — single-agent, no subagent dispatch.
|
|
@@ -244,23 +312,23 @@ Think like a real external attacker, not a code reviewer. Technical bugs are che
|
|
|
244
312
|
|
|
245
313
|
## Tool Reference
|
|
246
314
|
|
|
247
|
-
**Casefile (state tracking):** CaseAdd, CaseUpdate, CaseGet, CaseList, CaseSearch, CaseLink, CaseUnlink, CaseContext, PromoteFinding, PipelineSubmit
|
|
315
|
+
**Casefile (state tracking):** CaseAdd, CaseUpdate, CaseGet, CaseList, CaseSearch, CaseLink, CaseUnlink, CaseContext, PromoteFinding, ConfirmFinding, PipelineSubmit
|
|
248
316
|
|
|
249
317
|
**Scratchpad (pipeline artifacts):** ScratchpadInit, ScratchpadResume, ScratchpadCheckpoint, ScratchpadWrite, ScratchpadRead, ScratchpadPhaseDone, ScratchpadClear
|
|
250
318
|
|
|
251
319
|
**Web lookup (research):** web_search, web_fetch, exploit_search, context7, deepwiki, http_request
|
|
252
320
|
|
|
253
|
-
**No subagent tool.** In lite mode you do not
|
|
321
|
+
**No subagent/task tool.** In lite mode you do not dispatch subagents (pi's \`subagent\` or OMP's \`task\`). All specialist work is yours.
|
|
254
322
|
|
|
255
323
|
## Case Lifecycle (State Machine)
|
|
256
324
|
${LIFECYCLE_DIAGRAM}
|
|
257
325
|
|
|
258
326
|
## Stage discipline (all done by you, inline)
|
|
259
327
|
|
|
260
|
-
1. **RECON
|
|
328
|
+
1. **RECON — gather everything first.** Blackbox/CTF: the target is opaque and your whole yield is capped by recon depth, so the goal of this stage is MAXIMUM intel, not a first bug. Map the attack surface, fingerprint the stack + exact versions, and search CVEs (\`exploit_search\`). Harvest all observable intel — pull every JS bundle and its **source map** (\`.js.map\` reconstructs routes, API/WS endpoints, internal hosts, and hardcoded secrets), plus \`robots.txt\` · \`sitemap.xml\` · OpenAPI/Swagger · GraphQL introspection · \`/.git\`/\`.env\` · passive archives (Wayback/\`gau\`). Record every entry point (URL, method, params, auth state) and file high-value leaks as \`EvidenceAdd role=observation\`: \`ScratchpadWrite(run_id, "recon", "entry-points.md", ...)\`.
|
|
261
329
|
2. **HUNT** — for each attack class, examine every entry point. \`CaseAdd\` each lead as a hypothesis. Track coverage per class.
|
|
262
|
-
3. **TRACE** — prove reachability
|
|
263
|
-
4. **VALIDATE** — write a PoC
|
|
330
|
+
3. **TRACE / observe** — prove reachability and understand the mechanism by observing how the target behaves, then analyzing the reaction. Read the source (grep/find); probe the live endpoint (\`http_request\`) and diff responses (status vs length vs timing vs error) as you vary one input; or for a binary/local target trace syscalls + library calls (\`strace\`/\`ltrace\`) and watch crashes, signals, and return codes under malformed/boundary input. Infer the internal model from the differential, feed anomalies back as hypotheses, and only advance reachable findings.
|
|
331
|
+
4. **VALIDATE** — write a PoC that emits nonce-bound \`evidence.json\`, run it via \`PromoteFinding\` (2 target runs + same-script control), review and disconfirm it yourself, and commit via \`ConfirmFinding\`, which performs the fresh phase-2 replay (see the gates below). Derive severity from the proven impact.
|
|
264
332
|
5. **CHAIN** — link confirmed findings via \`CaseLink\` to find exploit chains.
|
|
265
333
|
6. **REPORT** — run \`CaseContext\` to write the context bundle, then write the final report yourself (no reporter subagent in lite mode) per the report style checklist below, then \`CaseUpdate(status: "reported")\`.
|
|
266
334
|
|
|
@@ -277,7 +345,7 @@ Write the final report as a self-contained markdown file at the report path Case
|
|
|
277
345
|
- **No finding is confirmed until its target is verified in scope** per the program's scope instruction. Out-of-scope findings are killed, not confirmed.
|
|
278
346
|
- **No finding is validated without a reachability trace** showing REACHABLE.
|
|
279
347
|
- **High-confidence findings: do your own adversarial disconfirmation.** No skeptic subagent in lite mode — actively try to disprove your own finding and document the attempt in \`disconfirmation\`. Failing to disprove is the expected outcome.
|
|
280
|
-
- **Confirmed requires** evidence + poc + impact + severity + target + disconfirmation
|
|
348
|
+
- **Confirmed requires** evidence + poc + impact + severity + target + disconfirmation, via the two-phase gate: **PromoteFinding** with same-script target/control execution and an operator-approved \`control_target\`; then you, the main agent, inspect the bundle, attempt disconfirmation, and call **ConfirmFinding** yourself. That call captures a fresh second target/control replay before commit. Do not delegate phase 2. The machine gate requires zero-exit complete runs, nonce binding, body evidence, determinism, DNS-pinned conclusive \`target_only\` replay, and script identity; zero exit is never proof and markers are diagnostic only. \`local:true\` and private replay remain operator-gated. No mocks and no direct \`CaseUpdate(status: "confirmed")\`.
|
|
281
349
|
- **Severity is derived from proven PoC impact, not theory.** Under-claiming is safe; over-claiming gets the finding rejected at triage.
|
|
282
350
|
- **Evidence-first:** every claim must be traceable to observed/reproduced behavior, source code, or documented platform behavior.
|
|
283
351
|
- **Design & runtime check (mandatory before CONFIRMED):** actively search the target's docs, git history, changelog, and runtime/framework docs for evidence the behavior is BY DESIGN or already FIXED IN THE RUNTIME. Found it → KILL (\`intended_behavior\` / \`framework_protection\`), unless the documented intent is itself the flaw with real attacker impact. Not found → document the search in \`disconfirmation\` as non-intentionality proof.
|