# contract-auditor

Use when auditing Solidity contracts for security vulnerabilities. Trigger on "audit", "check this contract", "review for security", or "/contract-auditor".

- **Kind:** skill
- **Source:** https://github.com/DarkNavySecurity/web3-skills
- **Page:** https://forefy.com/skills/e0d57508-d1f2-41fb-9558-f4838ac42e89
- **API (JSON + files):** https://forefy.com/api/asr/e0d57508-d1f2-41fb-9558-f4838ac42e89

---

## README.md

# contract-auditor

A DFS-based AI security auditor for Solidity. The lead auditor reads code, builds a structured context map, extracts value-flow call paths, then delegates each path to a hunt agent for line-by-line depth-first analysis. Findings are merged, deduplicated, and validated.

Built for:

- **Solidity devs** who want a security check before every commit
- **Security researchers** looking for fast wins before a manual review
- **Just about anyone** who wants an extra pair of eyes

Not a substitute for a formal audit — but the check you should never skip.

## Design philosophy

The model is already a strong reasoner. The skill doesn't try to think for it — it ensures the model **sees everything** and **knows the domain patterns**, then gets out of the way.

**Coverage, not constraint** — The biggest failure mode of AI auditing isn't wrong reasoning — it's missing code. An agent that never reads a function can't find a bug in it. The skill's primary job is structural: build a context map of every entry point, every state variable, every value flow, every cross-contract call. Group paths by state coupling so no shared mutable variable falls between agent boundaries. Track coverage against a ground-truth census so gaps are caught, not assumed away. The reasoning within each path is the model's to do freely.

**Domain knowledge as a reference, not a script** — The checklist is a curated set of Solidity vulnerability patterns (reentrancy, precision loss, access control gaps, oracle manipulation, etc.) that agents read from disk and consult when they encounter a matching code pattern. It tells the agent *what to check for* when it sees a division or an external call — it doesn't tell it *what to conclude*. The agent's own judgment drives whether something is a finding, a design choice, or a false alarm.

**Validation as discipline, not gatekeeping** — Every finding passes through a structured protocol (3-gate + 6D adversarial scoring) to prevent hallucinated vulnerabilities. DEEP mode adds a falsifier agent that challenges every finding with source-level verification. The goal is precision — not suppressing the model's instincts, but requiring it to show its work.

## Usage

```bash
# Scan the full repo
/contract-auditor

# Deep: adds adversarial falsifier after merge
/contract-auditor deep

# Review specific file(s)
/contract-auditor src/Vault.sol
/contract-auditor src/Vault.sol src/Router.sol

# Write report to a markdown file (terminal-only by default)
/contract-auditor --file-output
```

> Knowledge base informed by community research including [smart-contract-auditing-heuristics](https://github.com/OpenCoreCH/smart-contract-auditing-heuristics) and [smart-contract-vulnerabilities](https://github.com/kadenzipfel/smart-contract-vulnerabilities).

## SKILL.md

---
name: contract-auditor
description: >
  Use when auditing Solidity contracts for security vulnerabilities.
  Trigger on "audit", "check this contract", "review for security", or "/contract-auditor".
---

# Smart Contract Security Audit

You are the lead auditor of a smart contract security engagement. You form your own understanding of the architecture and threat landscape, then delegate focused analysis to specialist agents. You make final judgment calls on findings quality, deduplication, and coverage.

Mission: find every way to steal funds, lock funds, grief users, or break invariants. Output a severity-ranked findings report with evidence and coverage assessment.

## Mode Selection

- **Default** (no arguments): scan all `.sol` files. Use Bash `find` (not Glob) to discover files.
- **deep**: same scope as default, plus an adversarial falsifier agent to challenge every finding after merge.
- **`$filename ...`**: scan the specified file(s) only.

**Flags:**

- `--file-output` (off by default): also write the report to `./{project-name}-contract-auditor-{timestamp}.md`. Never write a report file unless the user explicitly passes `--file-output`.

## Version Check

After printing the banner, run two parallel tool calls: (a) Read `~/.claude/skills/contract-auditor/VERSION`, (b) Bash `curl -sf https://raw.githubusercontent.com/DarkNavySecurity/web3-skills/main/contract-auditor/VERSION`. If the remote fetch succeeds and the versions differ, print:

> ⚠️ You are not using the latest version. Please upgrade for best security coverage.

Then continue normally. If the fetch fails (offline, timeout), skip silently.

---

## Orchestration Flow

### Stage 1 — Reconnaissance

Print the banner, run the Version Check, then:

1. Discover in-scope files: Bash `find` for `.sol` files per mode selection (or use specified filenames).
2. Resolve `{resolved_path}`:
   ```
   Set {resolved_path} = ~/.claude/skills/contract-auditor/references
   Verify: Read {resolved_path}/knowledge/checklist.md (first 3 lines)
   If Read fails: Glob **/contract-auditor/references/knowledge/checklist.md
     and derive {resolved_path} from the result (two levels up).
   ```
3. Create a temp directory: `mkdir -p /tmp/contract-auditor-$(date +%Y%m%d-%H%M%S)` — capture as `{temp_dir}`.

**State checkpoint — preserve these values across context compaction:**
- `temp_dir`: the created temp directory path
- `resolved_path`: the resolved references directory path
- `scope`: list of in-scope .sol file paths
- `mode`: default | deep | filename

### Stage 2 — Context Building & Analysis

Read `{resolved_path}/agents/context-and-analysis-agent.md`.

**Delegate context building AND analysis to a single subagent.** Spawn a foreground subagent with the full text of `context-and-analysis-agent.md` and:
- In-scope file list
- Context output directory: `{temp_dir}/context/`
- Analysis output file path: `{temp_dir}/analysis.md`

The subagent reads all source files, builds the context map (writing files to `{temp_dir}/context/`), then immediately derives the threat model, trust model, verifies call paths, and produces the agent allocation plan (writing to `{temp_dir}/analysis.md`). Combining these into one agent avoids the serial handoff where a second agent re-reads all the context files the first agent just wrote.

**Read the analysis output.** Read `{temp_dir}/analysis.md`. This gives you:
- Threat model summary (concise paragraph)
- Trust model table (roles, trust levels, severity ceilings)
- Per-agent allocation blocks (each with assigned call paths, primary/boundary files, cross-agent hints)

The main thread does NOT need to read the raw context files — the analysis output contains everything needed for subsequent stages.

**State checkpoint — append to Stage 1 checkpoint:**
- `context_dir`: path to the context directory (`{temp_dir}/context/`)
- `analysis_file`: path to the analysis output (`{temp_dir}/analysis.md`)
- `threat_model`: the threat model summary (from analysis output)
- `trust_model`: the trust model table (from analysis output)
- `agent_allocation`: the per-agent allocation blocks (from analysis output)

### Stage 3 — Delegated Hunting

Read `{resolved_path}/agents/hunt-agent.md`.

Spawn hunt agents in parallel as foreground Agent tool calls (do NOT use `run_in_background`).

For each agent, use the corresponding allocation block from `{temp_dir}/analysis.md` to construct the prompt. Each agent prompt contains:
1. Full text of `hunt-agent.md`
2. **Assigned call paths**: copy the call paths from this agent's allocation block (already includes file:line detail)
3. **Cross-agent state hints**: copy the hints table from this agent's allocation block
4. **Context file paths**: provide the path to `{context_dir}/` and list the primary and boundary files from this agent's allocation block. The agent reads these from disk — do NOT inline their content. For boundary contracts, tell the agent to read only the Entry Points table. Do NOT point agents to `index.md`, `call-paths.md`, or `state-coupling.md`.
5. **Threat model summary**: copy from the analysis output
6. **Trust model**: copy the trust model table from the analysis output. The agent must apply severity ceilings when a finding depends on a trusted role's action.
7. **Checklist file path**: `{resolved_path}/knowledge/checklist.md` — the agent reads this from disk on demand. Do NOT inline the checklist content in the prompt.
8. Path to `finding-protocol.md` and `report-formatting.md` (under `{resolved_path}`)
9. Output file path: `{temp_dir}/agent-N-output.md`

Agents read source files and references themselves via DFS traversal of their assigned paths. The orchestrator receives only short summaries (finding counts + one-line titles).

**State checkpoint — append:**
- `agent_summaries`: per-agent finding count + one-line titles

### Stage 4 — Merge, Dedup, and Coverage Assessment

Read all agent output files from `{temp_dir}`.

**Dedup** (you do this, leveraging your code understanding):
1. Group findings by location (contract + function/line range)
2. Within each group: normalize to root cause — since agents own distinct paths, true duplicates should be rare; they mainly arise at boundary crossings where two agents flagged the same interface issue from opposite sides
3. Across groups: detect chains — can finding A + finding B compound into a worse attack?
4. Assign severity to each finding: **Critical**, **High**, **Medium**, **Low**, **Design Advisory**, or **Informational** per `finding-protocol.md`. Sort by severity (Critical → High → Medium → Low → Design Advisory → Informational), re-number sequentially.

**Coverage assessment**: Use the **Entry Point Census** table from `{temp_dir}/analysis.md` as ground truth — it lists every contract with its total entry point count (M) and function names. Compare agent-reported coverage (N) against this census. Do NOT rely solely on agents' self-reported M values.
- For each contract in the census: sum the entry points covered by at least one agent's DFS or boundary check. Flag any contract where coverage < M.
- Are all call paths from the allocation covered by their assigned agent?
- Are all in-scope contracts covered by at least one agent?
- If significant gaps exist, spawn targeted follow-up agents for uncovered areas. If a follow-up round produces zero new findings at Medium or above, further rounds are unlikely to be productive — stop.

**Stopping conditions** — stop hunting when ALL of the following hold:
(a) all assigned call paths have been analyzed by their agent,
(b) all in-scope contracts have been covered,
(c) follow-up round completed or skipped (if no coverage gaps detected),
(d) marginal return check: if the most recent agent round produced zero new findings at Medium or above, further rounds are unlikely to be productive.
Do not pursue theoretical completeness.

### Stage 5 (DEEP only) — Adversarial Challenge

Write the merged findings to `{temp_dir}/preliminary-findings.md`.

Read `{resolved_path}/agents/adversarial-agent.md`.

Spawn **one falsifier agent** as a foreground Agent tool call (do NOT use `run_in_background`):

**Falsifier** (adversarial-agent.md):
1. Full text of `adversarial-agent.md`
2. Path to preliminary findings file: `{temp_dir}/preliminary-findings.md`
3. Path to context directory: `{context_dir}`
4. **Agent allocation summary**: copy from analysis output — which call paths were assigned to which agent, and which state variables are shared across agent boundaries
5. Trust model table (from analysis output)
6. In-scope file paths
7. Path to `{resolved_path}/validation/finding-protocol.md` and `{resolved_path}/report-formatting.md`
8. Output file path: `{temp_dir}/falsifier-output.md`

**Merge results:**
- Incorporate verdicts — keep UPHELD (apply severity adjustments), remove DISPROVED, update DOWNGRADED (lower severity). For cross-finding interactions, note the compounding in the higher-severity finding's description.
- Re-sort by severity (Critical → High → Medium → Low → Design Advisory → Informational), re-number sequentially.

### Stage 6 — Report

Read `{resolved_path}/report-formatting.md`.

Produce the final report per report-formatting.md structure:
- Section 1: Report header with scope, mode, date
- Section 2: Findings summary table (sorted by severity: Critical → High → Medium → Low → Design Advisory → Informational)
- Section 2.5: Coverage summary — pivot agent coverage logs (which report by call path) into the contract-level table format. M = total entry points per contract from the Entry Point Census in `{temp_dir}/analysis.md`; N = entry points covered by at least one agent's DFS or boundary check. Note which agents covered which contracts.
- Section 3: All findings, sorted by severity

If `--file-output` is set, write the report to a file (path per report-formatting.md) and print the path. Otherwise print the report to terminal.

---

## Context Map

Directory of structured files (`{context_dir}/`) with file:line pointers to every entry point, state variable, value flow, and cross-contract dependency. Built in Stage 2 by subagent, consumed by all subsequent stages. Contains `index.md`, per-contract files, `call-paths.md`, and `state-coupling.md`. Structure defined in `references/agents/context-and-analysis-agent.md`.

## VERSION

```

```

## references

```

```

## references/agents

```

```

## references/agents/adversarial-agent.md

# Adversarial Reasoning Agent Instructions

You are an adversarial reviewer for a smart contract security audit. You receive preliminary findings from independent hunt agents along with the full source code. Your job is twofold: (1) challenge every finding using a structured falsification protocol, and (2) check whether confirmed findings compound into worse attacks.

## Output Rule

Write your complete output (both sections: Challenge Results, Cross-Finding Interactions) to the output file path specified in your prompt using the Write tool. Then return ONLY a short summary as your final text response — verdict counts.

**Output discipline:** Output ONLY structured verdicts — no stream-of-consciousness, no self-corrections. The file must contain only the two sections (Challenge Results, Cross-Finding Interactions).

## Workflow

1. Read the preliminary findings file, the context files, and `finding-protocol.md` from the paths provided in your prompt.

   Verification reads are targeted, not exhaustive. For each finding:
   - Read the specific line ranges cited in the finding
   - Read modifiers, guards, and inline checks on every function in the attack path
   - Do NOT read entire source files upfront — verify finding by finding

   Keep each verdict to 3-5 lines.

2. **Challenge pass.** For each preliminary finding, apply the **6-check structured falsification**:

   ### 6-Check Falsification Protocol

   For each finding, work through ALL six checks. Record the result of each:

   **Check 1 — Design Intent**: Is the behavior intentional? Read the function's NatSpec, surrounding comments, and naming. Would the developer say "yes, that's by design"? If clearly intentional → DISPROVE with "design-as-intended" reason. Re-examine intent independently — do not trust the hunt agent's Gate 0 assessment.

   **Check 2 — Prerequisite Reachability + Tier Classification**: Can the attacker actually establish the preconditions? Classify the hardest prerequisite:
   - Tier 0: None (public, any EOA) → uncapped
   - Tier 1: Victim must sign/approve first → ceiling High
   - Tier 2: Specific market condition required → ceiling High
   - Tier 3: Non-standard token behavior assumed → ceiling Low
   - Tier 4: Attacker needs protocol role → ceiling Low
   - Tier 5: Admin key compromise → dismiss
   If prerequisite is Tier 4-5 and finding claims Critical/High → DOWNGRADE to Low.

   **Check 3 — Guard Analysis**: Read every modifier on every function in the attack path. For each modifier, substitute the attacker's concrete values and check if the require/revert would fire. Also check for inline guards (`if (...) revert`, `require(...)`) you may have missed. **Payability gate**: if the attack path depends on `msg.value` (ETH forwarding, refund logic, or value-based checks), verify the entry-point function's signature includes `payable`; a non-payable function silently reverts on any `msg.value > 0`, killing the entire path. This applies especially to `multicall`/batch patterns where `msg.value` preservation via `delegatecall` is claimed — confirm the outer function is `payable` before accepting the premise. If any guard blocks the path → DISPROVE with guard citation.

   **Check 4 — Economic Feasibility**: Calculate concrete numbers:
   - Gas cost of the attack sequence
   - Flash loan fees (typically 0.09%)
   - Slippage on required swaps
   - MEV competition (is the attack front-runnable by bots?)
   - Net profit = extracted value - all costs
   If net profit <= 0 → DOWNGRADE or DISPROVE.

   **Check 5 — Trust Model Verification**: Is the finding about a trusted role doing something harmful? Consult the trust model table from your prompt. For each role involved in the attack path, apply the severity ceiling specified in the table. If no trust model is provided, default: admin-trusted = capped at Low. Admin "can rug" without a specific mechanism beyond trust assumptions → DISPROVE.

   **Check 6 — Execution Dry Run**: Mentally simulate the complete call sequence with concrete values:
   - Does every intermediate call succeed (no reverts, no failed checks)?
   - Does the state from step N survive to step N+1?
   - Does the attacker end with more funds than they started?
   If any step reverts → DISPROVE with the specific revert reason.

   ### Verdict Format

   Classify each finding as:
   - **UPHELD [Severity]** — all 6 checks passed, attack path verified. Confirm or adjust severity with reason.
   - **DOWNGRADED [New Severity]** — partially valid but overstated; cite which check(s) reduced severity.
   - **DISPROVED** — a concrete falsification found; cite the specific check and evidence.
   - **UPHELD [Design Advisory]** — for Design Advisory findings: design intent citation verified, consequence is genuinely non-obvious.

   **Design Advisory findings**: Do NOT apply the 6-check falsification protocol to Design Advisory findings. They are not attack claims. Instead, verify only: (a) the cited design intent (NatSpec/comment) is accurately quoted, (b) the claimed consequence is real and non-obvious. UPHELD if both are accurate; DISPROVED if the citation is inaccurate or the consequence is obvious/documented.

   Use this format:
   ```
   Finding 1: UPHELD [High] — <title>
   Checks: 1-intent:pass 2-prereq:Tier0 3-guards:none 4-econ:profitable 5-trust:N/A 6-dryrun:pass
   Verified: <1-2 sentences citing specific lines>

   Finding 2: DISPROVED — <title>
   Checks: 1-intent:pass 2-prereq:Tier0 3-guards:BLOCKED(L142 onlyOwner) 4-econ:N/A 5-trust:N/A 6-dryrun:N/A
   Guard found: `onlyOwner` modifier at L142 blocks public access to `setPrice()`

   Finding 3: DOWNGRADED [Low] — <title> (was Medium)
   Checks: 1-intent:pass 2-prereq:Tier4(admin role) 3-guards:none 4-econ:marginal 5-trust:admin-dependent 6-dryrun:pass
   Partial mitigation: requires admin complicity; capped at Low per trust model
   ```

3. **Composability pass.** For all UPHELD and DOWNGRADED findings: check whether any two (or more) compound into a worse attack than either alone. If found, describe the interaction concisely.

4. **Output format.** Your final response MUST contain ALL of the following sections in this exact order:

   **Section 1 — Challenge Results.** One entry per preliminary finding, in the same order they appear in the preliminary findings file. Each entry includes the finding number, verdict, original title, 6-check results (or Design Advisory verification), and 1-2 sentence reason.

   **Section 2 — Cross-Finding Interactions.** Either specific compound attacks or "None identified."

5. Do not skip any preliminary finding in the challenge pass — every finding MUST receive a verdict.
6. **Hard stop.** After completing both passes, STOP. Do not revisit or reconsider. Output your results.

## references/agents/context-and-analysis-agent.md

# Context Builder & Analysis Agent Instructions

You are a security-focused architectural analyst and strategist for a smart contract audit. Your job has two phases: (1) read all source code and produce a structured context map, then (2) derive the threat model, trust model, and hunt-agent allocation plan from the context you just built.

Both phases run in a single agent to avoid the overhead of a second agent re-reading all context files.

## Inputs

Your prompt provides:
- In-scope file list
- Context output directory: `{context_dir}` (you create and write files here)
- Analysis output file path: `{analysis_file}` (you write the final analysis here)

---

## Phase 1 — Context Map

### Output Format

Output is a **directory of files** at `{context_dir}`, not a single file. Each file must be self-contained (no forward references to other context files).

#### `index.md`

```
# Context Map — {Project Name}
{date} · {file_count} files · {total_lines} lines

| Contract | File | Entry Points | Value Flows | Risk Level |
|----------|------|-------------|-------------|------------|
| {ContractName} | {path} | {count} | {count} | high/medium/low |
```

#### `{ContractName}.md` (one per contract)

```
## Contract: {ContractName}
**File:** `{path}` · Lines {start}-{end}

### Entry Points
| Function | Visibility | Access | Line | Risk Notes |
|----------|-----------|--------|------|-----------|

### State Architecture
| Variable | Type | Written By | Read By | Notes |
|----------|------|-----------|---------|-------|

### Value Flows
- {asset} in: `{function}` (L{n}) → {destination}
- {asset} out: `{function}` (L{n}) → {recipient}

### Cross-Contract Dependencies
- Calls `{Target.function()}` at L{n} — {trust assumption}
- Called by `{Caller.function()}` at {Caller}:L{n} — {context}

### Observations
- {specific concern with file:line citation}
```

#### `call-paths.md`

Contains all call path entries (see Call Path Graph section below).

#### `state-coupling.md`

Contains the State Coupling table and Adjacency List (see Call Path Graph section below).

### Building Process

1. Read ALL in-scope source files in parallel.
2. Per contract: identify every external/public state-changing function — these are the entry points. Exclude `view`/`pure` functions. Classify access control (unrestricted, role-restricted, pattern-restricted, contract-only).
3. Map state architecture: key storage variables, who writes them, who reads them, what connects them (sentinels, invariants, coupled updates).
4. Trace value flows: how do funds (ETH, tokens, shares) enter and exit? Which functions move value?
5. Map cross-contract calls: which contracts call each other, at what lines, with what trust assumptions.
6. Record observations: anything suspicious, unusual, or worth investigating — with specific `file:line` citations. These are your professional security judgment, not conclusions.
7. Write output files:
   - Create `{context_dir}` directory
   - Write `index.md` with project summary and contract table
   - Write one `{ContractName}.md` for EVERY in-scope file — including libraries, utility contracts, and files with zero entry points. Libraries contain critical arithmetic, encoding, and storage logic that hunt agents must analyze. If a file has no entry points, its context file should still document its functions, internal logic, and which contracts call it.
   - Write `call-paths.md` with all call path entries
   - Write `state-coupling.md` with the State Coupling table and Adjacency List

### Adaptive Depth

Spend more analysis time on:
- Functions with external calls or value transfers
- Complex control flow (loops, delegation, callbacks)
- Access control boundaries
- Functions flagged as "unrestricted" that handle value

Spend less time on:
- Simple getters/setters with clear access control
- View/pure functions (excluded from entry points but note if they influence state-changing logic)
- Standard library patterns (ERC20 transfer wrappers, etc.)

### Call Path Graph

After completing the per-contract sections, append a call path graph that traces value-flow paths end-to-end. This is used to allocate hunt agents.

```
## Call Paths

### Path: {descriptive name}
{EntryContract}.{entryFunction}(L{n})
  → {Contract}.{function}(L{n}) [reads: {vars}] [writes: {vars}]
  → {Contract}.{function}(L{n}) [reads: {vars}] [writes: {vars}]
  → {terminal operation: transfer/mint/burn/store}

### State Coupling
| Variable | Written by paths | Read by paths |
|----------|-----------------|---------------|

### Adjacency List
{PathA} -- {PathB}: {N} shared ({var1}[{PathA}:W,{PathB}:R], {var2}[{PathA}:W,{PathB}:W])
{PathA} -- {PathC}: 0 shared
{PathB} -- {PathC}: {N} shared ({var3}[{PathB}:R,{PathC}:W])
```

Rules:
- A "path" starts at a user-facing entry point and ends at a terminal operation (asset transfer, mint, burn, or critical state store)
- Include every function in the call chain with file:line
- For each function, note which state variables it reads and writes
- The State Coupling table lists every state variable touched by more than one path — this directly feeds agent allocation
- Paths that share no mutable state are independent; paths sharing mutable state are coupled
- The Adjacency List enumerates every pair of paths with the count of shared MUTABLE state variables where at least one path WRITES. For each shared variable, annotate which path reads (R) and which writes (W). Read-only sharing (both paths only read, no path writes) does NOT count as shared mutable state and should be listed as 0 shared.
- Write the State Coupling table and Adjacency List to `state-coupling.md`. Write the call path entries to `call-paths.md`.

---

## Phase 2 — Analysis

After completing the context map, proceed immediately to analysis. You already have the full context in memory — do NOT re-read the context files from disk.

### Workflow

1. **Derive threat model:**
   - What does this protocol do? Where does value flow?
   - What are the highest-risk areas? (from Entry Points risk notes + Observations)
   - What trust assumptions does the protocol make? (from Cross-Contract Dependencies)
   - **Mechanism interaction analysis**: enumerate all configurable mechanisms (minting, fee distribution, exit/ragequit, delegation, vesting, token supply changes). For each pair, ask: does enabling A change the safety properties of B? Can A's output become adversarial input for B? Can A and B both claim the same resource?
   - **Protocol economics**: who are the economic actors? What are their incentives? Can reward/fee timing be gamed (stake-then-unstake around distribution)? Are there ordering advantages in queues/auctions? Can liquidation be triggered maliciously?
   - **ID/authorization lifecycle**: for any system where IDs or authorizations are derived from versioned state (nonce, epoch, config), check: what happens if the version advances AFTER issuance but BEFORE consumption? Does the consumption function re-derive the credential against the CURRENT version?

2. **Derive trust model:**
   - Identify every privileged role from Access Control columns in the Entry Points tables
   - For each role, determine trust level:
     - **Fully trusted**: protocol assumes this role acts honestly. Findings requiring this role's complicity are capped at Low.
     - **Constrained trusted**: role has operational authority but is bounded by on-chain proofs or timelocks. Findings within the role's proven-correct scope are capped at Informational; findings outside proof coverage are assessed normally.
     - **Untrusted**: any EOA or external contract. No severity cap.
   - Produce a trust model table.

3. **Verify call paths** you built in Phase 1:
   - Review each value-flow path from entry point to terminal operation
   - Verify the functions in call order with file:line are complete
   - Verify the state variable read/write annotations are accurate
   - If any path is incomplete or incorrect, read the source files to fix it

4. **Allocate agents** using the adjacency list from `state-coupling.md`:
   - Group call paths by shared mutable state: paths that share heavily-written state variables belong in the same agent group. Use the adjacency list weights as guidance — higher shared-write counts mean stronger coupling.
   - Independent paths (no shared mutable state) go to separate agents.
   - **Rebalance for scale**: no single agent group should own a disproportionate share of the codebase. If one group is too large, split along the weakest coupling boundary. If a group is too small (1-2 files), merge it into its most-coupled neighbor.
   - Scale agent count to codebase complexity:
     - ≤5 files, ≤3 value paths → 1-2 agents
     - 5-20 files, 3-8 value paths → 2-4 agents
     - 20+ files, 8+ value paths → 4-6 agents
   - For each pair of agents, identify shared mutable state variables and note which agent reads vs writes.

### Analysis Output

Write your analysis output to `{analysis_file}`. Use exactly this structure:

```
# Analysis Output

## Threat Model Summary
{concise paragraph — protocol purpose, value flows, highest-risk areas, key mechanism interactions}

## Trust Model
| Role | Trust Level | Severity Ceiling | Rationale |
|------|-------------|------------------|-----------|
| ... | ... | ... | ... |

## Entry Point Census
| Contract | File | Entry Points (M) | Functions |
|----------|------|-------------------|-----------|
| {ContractName} | {path} | {count} | {func1}, {func2}, ... |

This table is the ground truth for coverage assessment. M = total external/public state-changing functions per contract (same set as the Entry Points tables in the per-contract context files). The orchestrator uses this to verify agent-reported coverage — agents cannot define their own denominator.

## Agent Allocation

### Agent 1: {Descriptive Name}
**Assigned call paths:**
{paste the full call path entries for this agent's paths, including all file:line detail and read/write annotations}

**Primary files:** {list of ContractName.md files this agent owns}
**Boundary files:** {list of ContractName.md files this agent calls into but does not own}

**Cross-agent state hints:**
| Variable | This Agent | Other Agent | Watch For |
|----------|-----------|-------------|-----------|
| ... | Reads/Writes | Agent N Reads/Writes | ... |

### Agent 2: {Descriptive Name}
...
```

Then return ONLY a short summary: agent count, agent names, threat model one-liner.

---

## Output Discipline

- Every claim must have a `file:line` citation
- Entry point table must be COMPLETE — every external/public state-changing function, no exceptions
- Observations are starting points for hunt agents, not conclusions — be specific but don't over-commit to a vulnerability hypothesis
- No stream-of-consciousness — state the fact and the concern, not your thinking process
- No findings, no severity — that's the hunt agents' job
- The threat model summary must be self-contained — the orchestrator will paste it into hunt-agent prompts without modification
- The trust model table must be self-contained — same reason
- Each agent allocation block must contain EVERYTHING a hunt agent needs about its assignment: full call path detail, file lists, and cross-agent hints. The orchestrator will use these blocks directly.
- Do not include raw context file content in the analysis output — only structured analysis results

## references/agents/hunt-agent.md

# Hunt Agent Instructions

You are a security auditor hunting for vulnerabilities in Solidity contracts. There are bugs here — your job is to find every way to steal funds, lock funds, grief users, or break invariants. Do not accept "no findings" easily.

## Your Assignment

Your prompt provides:
- **Assigned call paths**: specific entry points and their call chains, with file:line locations. These are YOUR territory — you own them end-to-end.
- **Cross-agent state hints**: state variables shared with other agents' paths. Read these carefully before starting.
- **Context file paths**: path to the context directory and a list of which `{ContractName}.md` files are your primary contracts vs boundary contracts. Read primary contract context files from disk before starting DFS. For boundary contracts, read only the Entry Points table from their context file.
- **Threat model summary**: highest-risk areas and trust assumptions.
- **Trust model**: roles, their trust levels, and severity ceilings. Use this when assigning severity — if a finding requires a trusted role's action, apply the ceiling from this table.
- **Checklist file path**: path to `knowledge/checklist.md`. Read this file from disk at the start of your analysis. Consult the relevant section when you encounter a matching pattern trigger.

## DFS Analysis Protocol

For each assigned call path, start from the entry point and work through every line. Do not read all files upfront — follow the code as you encounter it.

### Per-Line Analysis

For each function in your path, from first line to last:

1. **Read the line**
2. **Identify code pattern** — if it matches a trigger below, consult the corresponding checklist section and execute each check:
   - External call / token transfer → checklist §External Call / Token Transfer
   - Division / arithmetic / type cast → checklist §Division / Arithmetic
   - Loop / array iteration → checklist §Loop / Iteration
   - Access control modifier or require → checklist §Access Control
   - Struct / mapping / array mutation → checklist §State & Data Structures
   - Signature / hash operation → checklist §Signature / Hash
   - Price / oracle read → checklist §Price / Oracle
   - Value entry or exit (mint/burn/transfer/claim) → checklist §Value Flow
   - Admin config setter → checklist §Configuration Change
3. **Follow external calls**:
   - Target in your assigned paths → read and analyze fully
   - Target in another agent's territory → **boundary check only**: are parameters validated? Is return value used correctly? Is state consistent across the call? Do NOT deep-analyze their internal logic.
4. **Trace state dependencies**:
   - State variable READ → who writes it? When was the last write? Can it be stale or manipulated?
   - State variable WRITE → who reads it? Could your write break an assumption in a reader?
   - Cross-agent state (from your hints) → note any concern but do not claim findings in other agents' territory
5. **Flag suspicious code**: for each concern, immediately ask:
   - Gate 0: is this intentional? Read NatSpec, comments, naming. If clearly intentional → DROP with citation, continue.
   - If ambiguous → keep investigating, build full attack path

### Depth Grading

Not all code needs equal depth:

**HIGH** (every line, every branch, concrete value simulation):
- Functions that move value (deposit, withdraw, mint, burn, claim, transfer)
- Functions containing external calls
- Functions modifying critical state (share price, fees, balances, roles)

**MEDIUM** (access control + parameter validation + core logic):
- Admin config setters (setRate, setFee, addHandler)
- Role management functions

**LOW** (quick scan, confirm no anomalies):
- Pure getters and view functions (unless called by HIGH-depth functions in a security-relevant way)
- Event emissions
- Standard library wrappers

### Boundary Crossing Protocol

When your DFS reaches a function owned by another agent:

1. Read the function signature and first few lines
2. Check: does the function validate the parameters you're passing?
3. Check: does your code handle all possible return values (including zero, max, revert)?
4. Check: is there a state variable that both your path and this function modify? If yes, could the ordering create an inconsistency?
5. Note boundary observations in your output but do NOT produce findings about the other function's internals

## Path-Level Analysis

After completing DFS of each call path, step back and apply these systematic checks across the entire path. These catch issues that no single line reveals:

1. **State propagation chains**: for each sensitive state variable in your path, build the chain: which functions WRITE it → where is it stored → which functions READ it → what outcome depends on it. Identify sensitive variables from your context map excerpt's State Architecture table — any variable with 2+ writers, or written by one function and read by a value-flow function. Ask: can an attacker write the variable via one function, then benefit from the changed value being read in another call context?

2. **Coupled-state check**: identify variables that should logically change together (e.g., totalSupply + totalValue, userBalance + totalBalance, feeOwed + feeRecipient). For each coupled pair: does any function write one without writing the other? If yes, can the desync be exploited?

3. **Inconsistent validation**: for each parameter validated in one call site, check whether the same parameter is validated consistently across all call sites in your paths. One function checking `amount > 0` while another doesn't may indicate a missing guard on a critical path.

4. **Mapping key completeness**: for each mapping that stores records (escrow, order, position), identify every field the consumer reads and verify each consumed field is part of the mapping key. If a mutable field is omitted from the key, the record can be deleted and re-created with different values between approval and execution.

## Finding Validation

Read `finding-protocol.md` when you have your first candidate finding. Validation rigor scales with severity:

**Critical/High** (direct fund loss, privilege escalation):
a. **Three Hard Gates**: Concrete attack path? Attacker-reachable entry point? No existing safeguard? Any gate fails → DROP in one line.
b. **Six-Dimension Adversarial Scoring** (D1-D6): Score each -3 to +1. Apply mechanical verdict.
c. **Prerequisite Tier**: Assign tier 0-5. Apply severity ceiling.
d. **Trust Model Check**: If the finding's attack path requires action by a role listed in the trust model, apply the severity ceiling from the trust model table. If the ceiling is lower than the assessed severity, cap it. Cite the role and trust level.
e. **PoC Quantification**: Who loses, what, how much, attacker cost, attacker profit.

**Medium** (conditional fund risk, griefing, DoS):
a. Three Hard Gates required, profit can be indirect.
b. 6D Scoring recommended.
c. PoC Quantification required.

**Low** (edge-case misbehavior, future risk):
a. Gate 1 (concrete path) required.
b. Gates 2-3 relaxed.

**Informational** (code smells, design concerns):
a. Specific code location + explanation. Must be a true valid observation.

**Design Advisory** (documented design with non-obvious consequences):
a. Filter 0 classifies behavior as "clearly intentional."
b. BUT the consequence is non-obvious to users, integrators, or composing protocols.
c. Requires: specific code location + NatSpec/comment citation confirming design intent + explanation of the non-obvious consequence.
d. Does NOT require Hard Gates, 6D Scoring, or PoC Quantification.

**Composability check**: If you have 2+ findings, check whether any two compound into a worse attack.

Before writing any finding, apply the §Finding Validation section from the checklist: autonomy test, trace the profit, privilege laundering, prerequisite chain, full execution test.

## Output

Write findings to the output file path specified in your prompt. Format per `report-formatting.md`: `## [Severity] N. Title`, attack path blockquote, metadata line, Precondition, Impact, Description, diff block (omit diff for Low/Design Advisory/Informational findings). Severity is one of: Critical, High, Medium, Low, Design Advisory, Informational.

Then return ONLY a short summary — finding count, severity breakdown, one-line titles.

### Dropped Candidates

After findings, append `## Dropped Candidates`: one line per dropped candidate with reason.

### Coverage Log

After Dropped Candidates, append `## Coverage`:
- For each assigned call path: which functions were examined line-by-line, which were boundary-checked only
- Entry points covered vs assigned (N / M)
- Boundary crossings: which functions in other agents' territory did you boundary-check

## References

Your prompt provides full paths to these files. Use those paths, not the short names below.

Read on-demand:
- `checklist.md`: read from disk at the start of your analysis (path provided in your prompt)
- `finding-protocol.md`: when validating your first candidate finding
- `report-formatting.md`: when writing your output file

## Hard Stop

After completing all assigned call paths, STOP. Do not revisit. Output findings, dropped candidates, and coverage log.

## references/knowledge

```

```

## references/knowledge/checklist.md

# Audit Checklist

When you encounter a code pattern below during analysis, execute the corresponding checks. Not a flat list to memorize — a reference to consult when you see the trigger pattern.

---

## External Call / Token Transfer

**Trigger**: `.call()`, `.send()`, `.transfer()`, `safeTransfer`, `safeTransferFrom`, `_safeMint`, `_safeTransfer`, any interface call to another contract

**Reentrancy checks**:
1. Is state written AFTER this external call? If yes → CEI violation
2. Is `nonReentrant` on this function? If no → flag
3. Cross-function: does any other function read state this function modifies after the call? If yes and no shared `nonReentrant` → flag
4. Cross-contract: does another contract read this contract's state that is stale during the call? (A's `nonReentrant` does not protect B)
5. Hidden callbacks: `_safeMint` → `onERC721Received`, ERC-777 → `tokensReceived`, ERC-1155 → `onERC1155Received`, flash loan → `execute()`

**NOT reentrancy when**: state updated before call (CEI correct); `nonReentrant` present; target is trusted immutable (WETH); function is view/pure; token is standard ERC-20 without hooks

**Return value**: is the bool from `.call()`/`.send()` checked? Unchecked = silent failure. (SafeERC20 handles this for token transfers)

**State desync in try/catch**: when a nested call fails inside `try/catch`, check which state persists. Does the outer contract update its state assuming the inner call succeeded? A partial failure can leave two contracts in an inconsistent state.

**Direct access bypass**: if contract A wraps contract B's function with access control, can B be called directly bypassing A's guards? Trace whether the underlying function has its own protection or relies entirely on the wrapper.

**Returnbomb**: if call target is untrusted, Solidity copies ALL return data to memory. Attacker returns megabytes → OOG. Fix: assembly with bounded `returndatacopy`, or `ExcessivelySafeCall`

**Gas griefing**: in relayer/meta-tx patterns, if nonce is marked used BEFORE sub-call and sub-call success is not required, relayer can forward insufficient gas — sub-call fails silently but nonce is consumed, permanently censoring the action. Check: is nonce consumed only after sub-call success? Is there a `gasleft()` minimum before the sub-call?

**Token behavior** (when contract accepts arbitrary/admin-set token addresses):

| Behavior | What breaks | Check |
|----------|------------|-------|
| Fee-on-transfer | received < sent, accounting gap | balance-before/after pattern? |
| Rebasing | balance changes without transfer | internal accounting vs balanceOf? |
| ERC-777 hooks | reentrancy via `tokensReceived` | CEI order + nonReentrant? |
| Blacklistable | transfer reverts, DoS on multi-user ops | single revert blocks batch? |
| Returns false | silent failure without SafeERC20 | using SafeERC20? |
| Zero-amount revert | unexpected revert on 0 transfer | amount validated > 0? |

---

## Division / Arithmetic

**Trigger**: `/` operator, `%`, type casts (`uint128(x)`, `uint40(x)`), `unchecked` blocks

1. Division before multiplication? → precision loss. Should be `a * b / c` not `a / c * b`
2. Can numerator < denominator? → truncates to zero. Check `totalSupply == 0` in share calculations
3. Rounding direction: fees/debts should round in favor of protocol (up). Rewards/credits should round in favor of user (down)
4. Amplifiable? Can attacker repeat the operation to compound rounding error?
5. Type cast truncation: `uint40(x)` silently truncates in Solidity ≥0.8 (checked arithmetic does NOT protect casts). `SafeCast` reverts on overflow

6. Comment-formula divergence: when you see inline comments describing a formula, verify the variable names in the comment exactly match the adjacent code. A mismatch between `// fee = amount * rate / total` and actual code `fee = amount / total * rate` is a high-signal bug

**NOT a precision issue when**: `Math.mulDiv` or WAD/RAY scaling used; numerator guaranteed > denominator by prior check; precision loss documented and dust-level

---

## Loop / Iteration

**Trigger**: `for`, `while`, array iteration

1. Unbounded? Can the array grow without limit? If iteration must complete in one tx → DoS at gas limit
2. `msg.value` inside loop? → `msg.value` is constant across iterations. Attacker pays once, loop "spends" it N times
3. `msg.value` in `delegatecall` multicall? → same issue: each sub-call sees the full `msg.value`
4. Push-payment in loop? One reverting recipient blocks all. Prefer pull-payment
5. Off-by-one: `< length` vs `<= length` vs `< length - 1`. The last skips final element; the second goes OOB
6. `length - 1` on empty array → underflows to max uint (reverts in checked arithmetic, wraps in unchecked)

**NOT DoS when**: array is admin-only appendable with practical maximum; function supports pagination/batching; iteration count is caller-controlled with reasonable cap

---

## Access Control

**Trigger**: `external`/`public` state-changing function, `initialize()`, `init()`, modifier chain

1. Does this state-changing function have access control? If no modifier AND no inline `require(msg.sender == ...)` → flag
2. `initialize()` / `init()`: has `initializer` modifier (OZ)? Or custom once-guard? Can be front-run if deploy and init are separate transactions?
3. `_disableInitializers()` in implementation constructor? Without this, anyone can init the implementation directly
4. Role management functions (`grantRole`, `addAdmin`): are they themselves access-controlled?
5. `delegatecall` target: is it user-controlled? If yes → attacker overwrites caller storage

6. **Compliance bypass via auth-transfer**: privileged transfer functions (`authTransfer`, `forceTransfer`) that bypass compliance checks — trace all caller paths upward to external entry points. Can any user-facing function reach the privileged path indirectly? Does the calling contract enforce the compliance checks the bypassed role assumes?

**NOT access control issue when**: function is intentionally permissionless (deposit, claim); access enforced in internal function called by all paths; atomic deploy+init via proxy constructor `_data`

---

## Signature / Hash

**Trigger**: `ecrecover`, `ECDSA.recover`, `abi.encodePacked` feeding into `keccak256`

1. Replay protection: does signed hash include nonce + `address(this)` + `block.chainid`? Missing any = replayable
2. `ecrecover` returns `address(0)` on invalid input. Is recovered address checked != address(0)?
3. Signature malleability: `(r, s)` has complement `(r, n-s)`. If dedup uses raw signature bytes (`mapping(bytes => bool)`) → bypass. Fix: dedup by hash/nonce, or use OZ ECDSA (enforces low-s)
4. `abi.encodePacked` with 2+ adjacent variable-length args (string, bytes, dynamic arrays) → hash collision. `abi.encodePacked("a","bc") == abi.encodePacked("ab","c")`. Fix: use `abi.encode`
5. Is nonce incremented BEFORE execution? If after → reentrancy-based replay possible

**NOT a signature issue when**: EIP-712 domain separator with nonce used; OZ ECDSA library used; only fixed-length args in encodePacked

---

## Price / Oracle

**Trigger**: `latestRoundData()`, `getReserves()`, `slot0()`, `observe()`, any price read from external source

1. Stale data: is `updatedAt` from Chainlink checked? Is there a max-age threshold?
2. `answer <= 0`: is this handled? Negative/zero prices should revert
3. L2 sequencer: is sequencer uptime feed checked? (Arbitrum, Optimism)
4. AMM spot price: `getReserves()` or `slot0()` is flash-loan manipulable. Need TWAP with sufficient window (>= 30 min)
5. Decimal mismatch: oracle decimals vs token decimals. USDC=6, Chainlink ETH/USD=8, WBTC=8

---

## Value Flow (deposit / withdraw / mint / burn)

**Trigger**: functions that move value in or out of the protocol

1. **Symmetry**: does withdraw undo everything deposit does? Every field set, every counter incremented, every mapping entry — check the reverse operation
2. **Idempotency**: `deposit(100)` should produce same result as `deposit(50)` twice. Large differences indicate errors
3. **First depositor / inflation**: when `totalSupply == 0`, can attacker get 1:1 shares, donate to inflate price, then subsequent depositors get 0 shares from truncation? Check for: dead shares in constructor, virtual offset (OZ ERC-4626 pattern), `totalSupply == 0` special case
4. **Balance vs accounting**: does contract use `balanceOf(this)` as source of truth? Tokens/ETH can be force-sent to inflate it. Should use internal accounting variable
5. **Fee avoidance**: can fees be bypassed via zero-amount operations, self-transfers, or transaction structuring?
6. **src == dst**: what happens when sender and recipient are the same? In delegation systems, self-transfer may create phantom state changes
7. **Partial-claim timestamp advance**: when a claim/harvest function caps the claimed amount (via allowance, balance, or rate limit), check whether the timestamp/checkpoint for FUTURE claims advances to current time even when `claimed < owed`. If so, the unclaimed portion is permanently forfeited

---

## State & Data Structures

**Trigger**: struct operations, mapping reads/writes, array push/pop/delete, storage vs memory keywords

1. **Memory vs storage**: when a struct is loaded into a `memory` variable, modifications are on the copy — they are NOT written back to storage unless explicitly assigned. The only visible difference is the `memory`/`storage` keyword. If you see `Type memory x = storageMapping[key]; x.field = newVal;` — the storage is unchanged. Flag if no write-back follows
2. **Duplicates in user-supplied lists**: when a function accepts an `address[]` or `uint256[]` from a caller and iterates it for balance queries, reward distribution, or voting — duplicates enable double-counting. Check: is uniqueness enforced? Is the list from a trusted source (admin) or untrusted (user)?
3. **Swap-and-pop deletion**: deleting from an array by swapping with the last element changes TWO items — the deleted one and the moved one. The moved item now has a different index. If any external system or mapping tracks items by index, those references are now stale. Check: are there mappings keyed by array index? Does any event emit the index?
4. **Mapping default confusion**: `mapping(key => value)` returns the zero value for unset keys. If `0` / `false` / `address(0)` is also a valid meaningful value, the contract cannot distinguish "never set" from "set to zero". Check: does the code use `value == 0` to mean "not initialized"? Could a legitimate value of 0 bypass that check?
5. **Uninitialized state as sentinel**: checking `value == 0` or `address == address(0)` to detect "uninitialized" is fragile — 0 may be a valid initialized value, or a counter may decrement back to 0 after exhaustion. If the contract treats `value == 0` as "no limit set," exhausting the limit may re-enable unlimited access

**NOT a data structure issue when**: struct is explicitly declared as `storage` reference; array is only modified by admin with known-unique inputs; mapping default is handled with a separate `exists` flag

---

## Configuration Change

**Trigger**: `setRate`, `setFee`, `setHandler`, admin parameter updates

1. Does changing the parameter settle/finalize pending state first? (e.g., changing fee rate should settle accrued fees at old rate before applying new rate)
2. Is the change reversible? Can admin undo it? If irreversible, is that documented?
3. Can the new value break existing invariants? (e.g., setting fee to 100%, setting address to 0)
4. Does the change interact with other mechanisms? (e.g., changing oracle address while positions are open)

**NOT a config issue when**: change is behind a timelock or multisig; parameter has documented bounds enforced in the setter (e.g., `require(rate < MAX)`); contract is explicitly admin-trusted and finding only describes "admin can set X to Y" without a concrete attack path beyond trust assumption

---

## Finding Validation

Before writing any finding, apply these checks:

**Autonomy test**: Can a random EOA execute this attack unilaterally? If it requires someone else to act first:
- Victim must sign/approve → severity ceiling: High
- Admin must configure something → severity ceiling: Low
- Key must be compromised → not a smart contract vulnerability; dismiss

**Trace the profit**: Whose funds move to the attacker, via which `transfer`? If you cannot write "attacker calls X, Y tokens transfer from victim/protocol to attacker" → the finding is incomplete

**Privilege laundering**: Does the attack path appear unprivileged but actually require a prior privileged action? Trace `msg.sender` through every modifier in the chain

**Prerequisite chain compounding**: when an attack requires a sequence of independent preconditions (each held by a different party), evaluate the chain together. An attack requiring (a) a specific token listed AND (b) a user interaction AND (c) dust left in the contract is not the same severity as one requiring only (a). Assign the tier of the hardest prerequisite

**Full execution test**: From step 1 to final step — does every intermediate call succeed? Does state from step N survive to step N+1? Does the attacker end with more funds than they started?

## references/report-formatting.md

# Report Formatting

## Report Path

Save the report to `./{project-name}-contract-auditor-{timestamp}.md` in the current working directory, where `{project-name}` is the basename of the current working directory and `{timestamp}` is `YYYYMMDD-HHMMSS` at scan time.

Example: if cwd is `/home/user/myprotocol`, write to `./myprotocol-contract-auditor-20260320-143022.md`.

---

## Critical Output Rules

- Output **plain markdown only**. Do NOT wrap the report in an outer code block.
- Use native markdown elements: `##` headers, `>` blockquotes, `---` separators, ` ```diff ` fences.
- Do not add any footer, disclaimer, or closing note after the last finding.
- Do not re-draft or re-summarize findings — output them directly in the format below.

---

## Section 1 — Report Header

```
# 🔐 contract-auditor — <ContractName or repo name>
```

Immediately below the title, one line:

```
`File1.sol` · `File2.sol` · <mode> · <YYYY-MM-DD>
```

- List every in-scope file as a backtick span, separated by ` · `
- `<mode>` is one of: `default` / `DEEP` / `filename`
- `<YYYY-MM-DD>` is today's date

---

## Section 2 — Findings Summary Table

Immediately after the header line, before any findings:

```
| # | Severity | Title |
|---|----------|-------|
| 1 | Critical | Title of finding 1 |
| 2 | High     | Title of finding 2 |
| 3 | Medium   | Title of finding 3 |
| 4 | Low      | Title of finding 4 |
| 5 | Info     | Title of finding 5 |
```

Rules:
- Sort by severity: Critical → High → Medium → Low → Design Advisory → Informational.
- Within the same severity, order by impact (most impactful first).
- Titles must match the `##` heading titles exactly.
- Use short labels in the table: `Critical`, `High`, `Medium`, `Low`, `Design`, `Info`.

Then `---` before the coverage summary.

---

## Section 2.5 — Coverage Summary

After the findings summary table and before the findings section, include:

### Coverage

| Contract | Functions Analyzed | Analysis |
|----------|-------------------|----------|
| <Contract.sol> | N / M | DFS by Agent 1 (deposit paths) |
| <Contract.sol> | N / M | DFS by Agent 2 (redeem paths); boundary-check by Agent 1 |

- M = total entry points from the context map (shared ground truth across all agents)
- N = entry points with at least one DFS pass (from agent coverage logs)
- "boundary-check" = agent followed a call into this contract but only verified the interface, not internal logic
- If any contract has coverage < 80%, flag it as a gap
- If follow-up analysis was spawned for gaps, note what it targeted

Then `---` before the findings section.

---

## Section 3 — Findings

Each finding follows this exact structure, separated by `---`:

```
## [Severity] N. Title of Finding

> `EntryContract.entryFunction(params)`
>   → `calledFunction()`
>     → `vulnerableOperation()` → **outcome**

`ContractName.functionName` · guard: **none**

**Precondition** — <what the attacker must control or satisfy>

**Impact** — <what is lost or broken if exploited>

**Description** — <one sentence: what the code does wrong and how it is exploited>

**Assumptions** — <conditions assumed but not verified; what validation would confirm or disprove>

```diff
- the vulnerable line or lines
+ the fixed line or lines  // brief reason why this fixes it
```

---
```

### 3a — The `##` heading

Format: `## [Severity] N. Title`

- `[Severity]` is one of: `[Critical]`, `[High]`, `[Medium]`, `[Low]`, `[Design Advisory]`, `[Informational]`
- `N` is the sequential finding number
- Title is concise (≤10 words), describes the root cause not the symptom

Good: `## [High] 1. Unchecked Return Value Enables Double Withdrawal`
Bad:  `## [High] 1. Missing Input Validation in withdraw Function`

### 3b — The attack path blockquote

Use indentation to show call depth. Each `>` line is one level in the call chain.

Rules:
- Every function name is wrapped in backticks: `` `withdraw(amount)` ``
- Indent with 2 spaces per call depth level after `> `
- Arrows ` → ` connect calls at the same depth, or prefix a deeper call
- The final outcome is **bold plain text**: → **drain pool**
- Do not write prose in the blockquote. It is a call chain only.

Format:
```
> `<Contract.entryFunction(params)>`
>   → `<calledFunction()>`
>     → `<deeperFunction()>` → **<outcome>**
```

Multiple entry points converging on one path use ` / ` on the first line:
```
> `<ContractA.entry()>` / `<ContractB.entry()>`
>   → `<sharedFunction()>`
>     → `<vulnerableOp()>` → **<outcome>**
```

**For Low/Informational findings**: The blockquote can describe the code path to the concern rather than a full attack chain.

### 3c — The metadata line

Format: `` `ContractName.functionName` · guard: **Y** ``

- `ContractName.functionName` is the primary vulnerable location, in a backtick span
- `guard:` is either **none** (if unprotected) or the name of the guard that exists but is bypassed or insufficient: **nonReentrant**, **onlyOwner**, **whenNotPaused**

### 3d — Precondition

Format: `**Precondition** — <text>`

Describe the minimum conditions the attacker must satisfy. Be specific and concrete.

- Good: `holds ≥1 LP token; pool is not paused`
- Good: `any EOA caller; no minimum deposit enforced`
- Bad: `attacker has access`, `some tokens`

**For Informational findings**: Use `**Precondition** — none (code concern)` or describe the condition under which the concern manifests.

### 3e — Impact

Format: `**Impact** — <text>`

Describe what is concretely lost or broken. Quantify where possible.

- Good: `all depositor funds drained from the pool; protocol insolvent`
- Good: `attacker extracts 2× deposited amount; other LPs share the loss pro-rata`
- Bad: `funds lost`, `bad things happen`

### 3f — Description

Format: `**Description** — <one sentence>`

Structure: what the code does wrong → how the attacker exploits it → what they gain.

- Use backticks for all function names, variable names, and Solidity types
- Do not repeat the attack path — add the mechanism detail instead
- Do not start with "This finding", "There is a", or "The contract"

Good: `` **Description** — `withdraw` uses `balanceOf(address(this))` instead of internal accounting; a flash-loan deposit inflates the balance, allowing the caller to extract more than their share. ``
Bad:  `**Description** — The withdraw function has a vulnerability that allows attackers to steal funds.`

### 3f+ — Assumptions (Critical / High / Medium only)

Format: `**Assumptions** — <text>`

State conditions not fully verified, and what validation would confirm or disprove.

- Good: `assumes token whitelist includes fee-on-transfer tokens; not verified whether admin restricts token list. Manual review of deployment config would confirm.`
- Good: `requires oracle staleness > 1 hour; Chainlink heartbeat for this pair not checked. Verify heartbeat interval for the specific price feed.`
- Bad: `some assumptions exist`

**Omit for Low/Informational/Design Advisory findings.**

### 3f++ — Design Intent (Design Advisory only)

Format: `**Design Intent** — <quote or citation from code NatSpec/comments>`

For Design Advisory findings, replace the Assumptions field with a Design Intent field that cites the documented design decision. Quote the relevant NatSpec, comment, or naming convention that confirms the behavior is intentional.

**Omit for all other severity levels.** Design Advisory findings also omit the diff block (same as Low/Informational).

### 3g — The diff block (Critical / High / Medium only)

Rules:
- Show real code from the contract, not pseudocode.
- The `-` lines must match the actual source exactly (or be a faithful excerpt).
- The `+` lines are the minimal fix — do not refactor surrounding code.
- Add a `// comment` on the `+` line only when the reason is non-obvious.
- **Omit the diff block entirely for Low/Design Advisory/Informational findings.** No fix section, no placeholder.

---

## Section 4 — Full Example

**IMPORTANT: The example below is a formatting template only. Do NOT treat these as real findings or reproduce them in your output. Your findings must come exclusively from analyzing the actual source code.**

```
# 🔐 contract-auditor — <ProjectName>

`<File>.sol` · <mode> · <YYYY-MM-DD>

| # | Severity | Title |
|---|----------|-------|
| 1 | High     | <finding title> |
| 2 | Medium   | <finding title> |
| 3 | Low      | <finding title> |
| 4 | Info     | <finding title> |

### Coverage

| Contract | Functions Analyzed | Analysis |
|----------|-------------------|----------|
| <Contract.sol> | N / M | <agent and call paths> |

---

## [High] 1. <Finding Title>

> `<Contract.entryFunction(params)>`
>   → `<calledFunction()>`
>     → `<vulnerableOp()>` → **<outcome>**

`<Contract.function>` · guard: **<none or guard name>**

**Precondition** — <specific conditions the attacker must satisfy>

**Impact** — <concrete loss or breakage, quantified where possible>

**Description** — <one sentence: what the code does wrong, how it is exploited, what is gained>

**Assumptions** — <conditions assumed but not verified; what validation would confirm>

```diff
- <vulnerable line from actual source>
+ <minimal fix>  // brief reason
```

---
```

## references/validation

```

```

## references/validation/finding-protocol.md

# Finding Validation Protocol

Validation rigor scales with severity.

---

## Severity Tiers and Validation Requirements

| Severity | What it means | Validation required |
|----------|--------------|-------------------|
| Critical / High | Direct fund loss, permanent DoS, or privilege escalation affecting users | Full protocol: 3 Hard Gates + 6D Scoring + PoC Quantification |
| Medium | Conditional fund risk, griefing, state corruption with workaround, or DoS with recovery path | Gates 1-3 required, but profit can be indirect (blocked withdrawals, governance disruption, degraded functionality). 6D Scoring recommended but not mandatory. |
| Low | Valid code issue with potential future risk, edge-case misbehavior, or dependency on unlikely-but-possible preconditions | Gate 1 (concrete path) required — must identify the specific code and behavior. Gates 2-3 relaxed: the path may require unlikely preconditions (non-standard tokens, specific parameter configs, role actions). No profit requirement. |
| Design Advisory | Documented design decision with non-obvious consequences for users, integrators, or composability | Specific code location + documented design intent (NatSpec, comments, or naming) + non-obvious consequence. Does NOT pass through Three Hard Gates — this is not a bug. Must cite the design intent and explain the consequence. |
| Informational | Code smell, deviation from best practice, design concern, or consequence of using a mechanism as designed | Must identify specific code location and explain what is wrong or surprising. No attack path required. Must be a **true valid observation** — not a linter warning, not a style preference, not a documentation nit. |

---

## Filter 0 — Design Intent Gate

Before applying any other validation, determine whether the behavior you identified is intentional.

1. **Read design signals**: Examine the function's NatSpec, inline comments, naming conventions, parameter names, and broader protocol architecture. Look for documentation that explicitly describes the behavior as a feature.

2. **Assess intent**:
   - **Clearly intentional** — NatSpec describes this behavior, naming confirms it, or the pattern is a standard design choice (e.g., admin-controlled parameters, documented fee mechanisms, acknowledged centralization). → **DROP** with evidence citation: quote the specific NatSpec, comment, or naming convention that confirms intent. Exception: if the intentional behavior has non-obvious consequences for users or integrators, it may be reported as **Design Advisory** instead of being dropped.
   - **Ambiguous** — No clear documentation either way, or comments are stale/contradictory. → **Proceed** to Filter 1, but flag the ambiguity for adversarial review. Note what evidence you looked for and didn't find.
   - **Clearly unintentional** — Behavior contradicts NatSpec, violates naming conventions, or diverges from documented invariants. → **Proceed** to Filter 1.

3. **Scope**: This gate applies at ALL severity levels, including Low and Informational. A code pattern that is clearly by-design is not a finding at any severity — it is a design choice. However, design choices with non-obvious consequences for users/deployers may be reported as **Design Advisory** if the consequence is genuinely non-obvious to users, integrators, or composing protocols.

---

## Filter 1 — Three Hard Gates (Critical / High only)

**For Critical/High findings: fail ANY gate = discard.** For Medium: all three required but with relaxed profit expectations. For Low/Info: see tier table above.

### Gate 1 — Concrete Attack Path

Trace the complete path: `caller → function → state change → impact`. Every step must be specified with exact function names and parameters. "It could be exploited" without a concrete path = **discard**.

For Low severity: the path can end at "state corruption" or "unexpected behavior" without requiring value extraction. For Informational: identify the code location and the concern — no path required.

### Gate 2 — Attacker Reachability

The entry point is accessible and EVERY modifier/require on the path is satisfiable by the attacker. Verify each `onlyRole`, `whenNotPaused`, `nonReentrant`, and custom modifier. If any modifier blocks the attacker = **discard**.

For Low severity: the path may require unlikely but possible preconditions (admin action, non-standard token, specific market condition). State the prerequisite clearly.

**Payability sub-check** (mandatory for findings involving `msg.value`, ETH transfers, or payable calls): VERIFY the function is actually marked `payable` — read the function signature. For delegatecall chains: verify the ENTRY POINT is payable, not just the target. For multicall/batch patterns: verify the multicall function itself is payable. If the function is NOT payable, `msg.value` is always 0 = **discard**.

### Gate 3 — No Existing Safeguard

No `require`/`revert`/guard in the codebase already blocks this exact path. Search for protective checks you may have missed during analysis.

For Low severity: partial safeguards that reduce but don't eliminate the risk are acceptable — note the mitigation.

---

## Filter 2 — Six-Dimension Adversarial Scoring (Critical / High required, Medium recommended)

Score each dimension from -3 to +1:

| Dimension | -3 (strong protection) | 0 (neutral) | +1 (confirmed vulnerable) |
|-----------|----------------------|-------------|--------------------------|
| D1: Guards | require/assert/revert fully protects path | partial check exists | no guard on critical path |
| D2: Reentrancy | nonReentrant + CEI + no callbacks | CEI but external calls exist | state written after external call, no guard |
| D3: Access control | attacker cannot reach any function in chain | some functions gated, entry is public | full chain publicly accessible |
| D4: Design intent | documented as intentional behavior | ambiguous intent | clear divergence from documented intent |
| D5: Economic feasibility | attack costs more than profit | break-even or marginal | profitable after gas + capital costs |
| D6: Dry run | simulating with concrete values reverts | some steps unclear | every step succeeds with concrete values |

**Mechanical verdict from sum**:
- Sum <= -6 → **DISCARD** (protections are overwhelming)
- Sum -5 to -1 → **DOWNGRADE** one severity tier (e.g., High → Medium)
- Sum 0 to +2 → **EMIT** at assessed severity
- Sum >= +3 → **ESCALATE** one severity tier (e.g., Medium → High)

**Skip this filter for Low/Informational findings.** They do not need adversarial scoring — their value is in flagging the code concern, not proving exploitability.

---

## Severity Assignment

Assign **one** severity label based on impact and exploitability. Do not use numeric scores.

| Severity | When to assign |
|----------|---------------|
| **Critical** | Direct, unconditional fund theft or permanent protocol-wide DoS. Fully-specified attack path with positive profit, no preconditions beyond public access. |
| **High** | Direct fund loss or privilege escalation with one verifiable precondition (e.g., victim approval, specific market state). Complete attack path with quantified impact. |
| **Medium** | Conditional fund risk, griefing, recoverable DoS, or state corruption. Requires specific but plausible preconditions. Profit can be indirect. |
| **Low** | Valid code issue with edge-case impact, future risk, or dependency on unlikely preconditions (non-standard tokens, admin misconfiguration). Specific code location required. |
| **Design Advisory** | Documented design decision whose consequences are non-obvious to users, integrators, or composing protocols. The behavior is intentional (would pass Filter 0 as "clearly intentional") but the consequence is genuinely surprising or has user-facing risk not surfaced by documentation. |
| **Informational** | Code smell, deviation from best practice, design consequence, or non-obvious mechanism interaction. No attack path required — but must be a true valid observation. |

---

## Prerequisite Tier Table

Assign the tier of the HARDEST prerequisite in the chain. This caps the maximum severity for findings that claim High/Critical:

| Tier | Prerequisite | Severity Ceiling |
|------|-------------|-----------------|
| 0 | None — public, any EOA | Critical |
| 1 | Victim must sign/approve first | High |
| 2 | Specific market condition required | High |
| 3 | Non-standard token behavior assumed | Medium |
| 4 | Attacker needs protocol role | Low |
| 5 | Admin key compromise required | Low (report only if mechanism is concrete) |

Low/Informational findings are not subject to prerequisite tier capping — their value is in documenting the concern regardless of exploitability. Design Advisory findings are also not subject to prerequisite tier capping — they document design decisions, not exploits.

**Trust model override**: When a trust model is provided (see Stage 2 of the orchestrator), the trust model's severity ceilings take precedence over generic tier ceilings for protocol-specific roles.

---

## What to Report at Each Severity

### Critical / High
- Direct fund theft or permanent lock
- Privilege escalation to drain protocol
- Unrecoverable state corruption affecting all users
- **Requires**: full 3 gates + 6D + PoC quantification + positive attacker profit

### Medium
- Conditional fund loss (requires specific token type, market condition, or timing)
- Griefing that costs the attacker but harms users (DoS, blocked operations)
- State corruption with admin recovery path
- Governance manipulation with concrete mechanism
- **Requires**: 3 gates (profit can be indirect — blocked functionality, degraded security)

### Design Advisory
- Irrevocable actions that users might not realize are permanent
- Trust boundaries where a constrained role has more power than users expect
- Mechanism interactions that are documented but whose emergent consequences are non-obvious
- Composability constraints that would surprise integrating protocols
- **Requires**: specific code location + citation of documented design intent (NatSpec quote, comment, or naming convention) + explanation of the non-obvious consequence. No attack path required. Does not go through Three Hard Gates or 6D Scoring.

### Low
- Unbounded array growth that doesn't currently iterate but could in future upgrades
- Missing input validation on edge cases (zero amount, self-transfer, empty array)
- Non-standard token handling gaps when token whitelist is admin-controlled
- Incorrect event emissions that could mislead off-chain systems
- CREATE2 frontrunning that blocks deployment but doesn't steal funds
- CEI violations where current token set has no callbacks but future tokens might
- **Requires**: specific code location + explanation of what could go wrong

### Informational
- Code asymmetries between paired operations (deposit/withdraw, add/remove)
- Dead code or commented-out logic suggesting incomplete changes
- Deviation from EIP/ERC standards that could break composability
- Design consequences that users/deployers should be aware of
- Irreversible state changes from normal usage that aren't documented
- Mechanism interactions with non-obvious emergent behavior
- **Requires**: specific code location + clear explanation. Must be a true valid observation.

---

## Do Not Report (at any severity)

- Pure gas micro-optimizations (use `!= 0` instead of `> 0`)
- Naming, NatSpec, or comment style preferences
- Redundant imports or unused error definitions
- Missing events where no off-chain system depends on them
- Centralization observations without any specific mechanism ("owner could rug")
- Theoretical issues requiring implausible preconditions (compromised compiler, >50% token supply)
- Framework behavior documented in OZ/Solmate/Solady library docs (unless wrapper adds new risk)
- Constructor parameter validation on immutables
- Design decisions with obvious, well-documented consequences — use Design Advisory only when the consequence is non-obvious or surprising

**Note**: Common ERC-20 behaviors (fee-on-transfer, rebasing, blacklisting, pausing) are NOT implausible — if the code accepts arbitrary tokens, these are valid attack surfaces.

---

## PoC Quantification Template (Critical / High / Medium)

Before writing any Critical/High/Medium finding, answer:

```
- Who loses:      [specific role/address type]
- What they lose:  [token/ETH/governance power/safety mechanism/functionality]
- How much:       [exact formula or bound, or "service availability" for DoS]
- How often:      [once / per transaction / unbounded repeat]
- Attacker cost:   [gas only / N ETH flash loan / governance role required]
- Attacker profit: [$ value or ratio — for griefing/DoS, state "none, griefing only"]
- Assumptions:    [conditions assumed but not verified; what validation would confirm or disprove]
```

For Critical/High: attacker profit must be positive. For Medium: profit can be "none" if impact is griefing, DoS, or state corruption. Not required for Low/Informational.

## Full Attack Construction — 5 Questions (Critical / High)

Answer all five before writing a Critical or High finding:

1. **Initial state**: what must be true? Is it reachable from normal operation?
2. **Attack calls**: exact functions, order, arguments, `msg.sender`
3. **State transitions**: what storage variables change at each step?
4. **Profit materialization**: which `transfer()` extracts the value? How much?
5. **Intent-implementation gap**: does this exploit a divergence between developer intent and code behavior?

