# client-auditor

Use when auditing, reviewing, or finding vulnerabilities in a blockchain node, execution client, consensus client, or any Go/Rust/C++ codebase with P2P networking, consensus logic, RPC handlers, or bridge components.

- **Kind:** skill
- **Source:** https://github.com/DarkNavySecurity/web3-skills
- **Page:** https://forefy.com/skills/e8159ab0-c138-4c3b-b280-afcad26ca796
- **API (JSON + files):** https://forefy.com/api/asr/e8159ab0-c138-4c3b-b280-afcad26ca796

---

## README.md

# Blockchain Client Auditor

![client-auditor overview](../images/client-auditor.jpg)

A Claude Code skill for security auditing of blockchain node implementations. Covers execution clients, consensus clients, app-chain SDKs, bridges, and any codebase with P2P networking or consensus logic — written in Go, Rust, C/C++, etc.

---

## What it does

The skill runs a **structured 7-stage audit** using an orchestrator + subagent architecture. The main context acts as coordinator and never reads source code or pattern files directly — all deep analysis is delegated to specialized subagents that write findings to disk as they confirm them.

**Stages:**
1. **Setup** — creates output directories, records audit parameters
2. **Recon** — maps codebase structure, entry points, trust boundaries, and applicable patterns
3. **Hunt** — parallel subagents analyze assigned subsystems against 20 vulnerability pattern families
4. **Cross-subsystem** — traces trust boundary mismatches at subsystem call sites
5. **Validation** — deduplicates findings, applies severity override rules
6. **Adversarial review** *(deep mode)* — Red Team / Blue Team / Judge protocol for HIGH+ findings
7. **Report** — consolidated report from disk state

**Knowledge base:**
- **20 vulnerability pattern families** covering input validation, consensus correctness, resource exhaustion, memory safety, concurrency, serialization, and more
- **7 structured analysis lenses** for systematically examining code at trust boundaries
- **Heuristic strategies** for finding bugs that patterns alone won't catch
- **A judgment framework** with false-positive gates, confidence scoring, and severity classification

---

## Design philosophy

- **Orchestrator + worker.** The main context stays lean — it coordinates and validates but never reads source code or pattern files. Subagents do all the deep work. This allows the audit to complete on large codebases (70K+ lines) without context compaction.
- **Handbook, not pipeline.** Hunt agents receive the full vulnerability handbook and explore freely — patterns, checklists, and heuristics are references to consult, not a sequence to execute. The agent decides what to read, where to dig, and when to stop.
- **Findings flow continuously.** Confirmed findings are written to disk as they're verified, not held until the end. The audit is resumable if interrupted.
- **Honest coverage over false completeness.** "3 confirmed findings in P2P handlers; consensus subsystem not analyzed" beats "comprehensive audit, 100% coverage" that isn't true.
- **Highest risk first.** Spend time proportional to risk (per the trust boundary model), not proportional to code volume.

---

## Install

Follow the [Claude Code skills installation guide](https://docs.anthropic.com/en/docs/claude-code/skills).

```
Install skill https://github.com/DarkNavySecurity/skills/client-auditor
```

---

## Usage

```
/client-auditor [target-path] [deep]
```

| Argument | Meaning |
|----------|---------|
| `target-path` | Path to audit. Use `.` for the current directory. Required. |
| `deep` | Enables adversarial review (Red Team / Blue Team / Judge) for high-severity findings. |

**Examples:**

```bash
# Audit the current repo
/client-auditor .

# Audit a specific subdirectory
/client-auditor ./node

# Full deep audit with adversarial review
/client-auditor . deep
```

---

## Knowledge base

### Vulnerability patterns (20 families)

| ID | Name | Applicability |
|----|------|---------------|
| P1 | Negative / illegal input triggers unrecoverable panic | All clients |
| P2 | Error handling defect in batch processing loops | All clients |
| P3 | EVM compatibility layer impedance mismatch | EVM clients only |
| P4 | Validator set / staking hook state inconsistency | All clients |
| P5 | Vote / signature deduplication failures | All clients |
| P6 | Non-determinism in consensus-path execution | All clients |
| P7 | RPC handler crash via malformed request | All clients |
| P8 | Fee grant and fee deduction errors | Complex fee systems only |
| P9 | P2P resource exhaustion (DoS without rate limit) | All clients |
| P10 | Bridge / cross-layer message integrity | Bridge clients only |
| P11 | Unbounded compute in consensus paths | All clients |
| P12 | ZK circuit under-constraint | ZK clients only |
| P13 | Charge ordering and gas accounting errors | All clients |
| P14 | Replay and double-spend | All clients |
| P15 | Precision loss and rounding manipulation | All clients |
| P16 | Wiring failures (handler registered to wrong route) | All clients |
| P17 | Memory safety (C/C++ and unsafe Rust) | C/C++, unsafe Rust only |
| P18 | Concurrency and data races | Multi-threaded only |
| P19 | Undefined / implementation-defined behavior | C/C++ only |
| P20 | Serialization boundary hardening | All clients |

### Analysis techniques

- **Analysis checklist** — 7 lenses: branch exhaustion, zero-trust message check, data lifetime trace, quantitative resource accounting, missing-defense inventory, thread safety, memory safety
- **Heuristic strategies** — structural suspicion, complexity signals, temporal assumptions, cross-boundary data flow, cross-subsystem interactions, implicit global state
- **Adversarial review** — Red Team / Blue Team / Judge protocol for stress-testing high-severity findings

### Judgment framework

- **3-check false-positive gate** — concrete execution path, external reachability, no sufficient existing guard
- **Confidence scoring** — start at 100, apply deductions for admin requirements, key compromise prerequisites, quorum thresholds, non-default config, partial mitigations, etc.
- **Severity classification** — Critical (chain-wide, ≥80), High (≥70), Medium (40-69), Low (20-39), Info (<20)
- **Override rules** — caps for admin-only, trusted-party key, quorum-required, self-recovering, and unreachable-path findings

---

## Output

All output is written to `audit/` in the working directory:

```
audit/
  metadata.md          — audit parameters (target, date, mode)
  manifest.md          — recon output: subsystem map, entry points, applicable patterns
  findings/[ID].md     — one file per confirmed finding, written as confirmed
  progress/[name].md   — subsystem checkpoints (for resume after interruption)
  report.md            — final consolidated report
```

Run `ls audit/findings/` at any time during the audit to see confirmed findings as they land.

Each finding includes:

```
Severity    — Critical / High / Medium / Low / Informational
Confidence  — 0–100 score after applying deduction table
Pattern     — P1–P20 family that matched (or "heuristic finding")
Location    — file:line_start–line_end
Entry point — how an attacker reaches this code
Description — what the code does, what it fails to do, attacker outcome
Trigger     — step-by-step attack scenario
Quantitative impact — cost × rate × messages = total; time to impact
Existing mitigations — every partial defense, with effectiveness
Missing defenses     — what should be here but isn't
Recommendation       — concrete fix with code location reference
Adversarial review   — [deep only] Red/Blue/Judge verdict table
```

The report opens with an executive summary, includes findings by severity, and closes with an honest coverage summary describing what was and wasn't analyzed.

---

## Scope

**Works well on:**
- Execution clients (e.g., go-ethereum, Erigon, Reth, Nethermind, Besu)
- Consensus clients (e.g., Lighthouse, Prysm, Teku, Nimbus, Lodestar)
- App-chain SDKs (e.g., Cosmos SDK, Substrate, Tendermint/CometBFT)
- Custom chains and L2 node implementations
- Bridge and relayer codebases
- Any codebase with P2P networking, RPC servers, or consensus logic

**Notes:**
- For very large codebases, specify a subdirectory to focus the audit
- Deep mode is slower; budget extra time for adversarial review
- Cryptographic implementation correctness requires specialist review beyond pattern matching

## SKILL.md

---
name: client-auditor
description: >
  Use when auditing, reviewing, or finding vulnerabilities in a blockchain node,
  execution client, consensus client, or any Go/Rust/C++ codebase with P2P networking,
  consensus logic, RPC handlers, or bridge components.
allowed-tools: Read, Grep, Glob, Bash, Agent, Write
metadata:
  argument-hint: "[target-path] [deep]"
---

# Blockchain Client Auditor

You are the **orchestrator** for a blockchain client security audit. You coordinate specialized subagents that do the deep code reading and pattern matching. Your job is to: understand the target architecture, delegate analysis to subagents, validate their findings, and produce the final report.

**Arguments:**
- `target-path` (required): Path to the codebase or subdirectory to audit. `.` for current directory.
- `deep` (optional): Apply adversarial review to HIGH+ findings.

**Version check:** Read `~/.claude/skills/client-auditor/VERSION` and fetch `https://raw.githubusercontent.com/DarkNavySecurity/web3-skills/main/client-auditor/VERSION`. If remote version is higher, print: `⚠️ You are not using the latest version. Please upgrade for best security coverage.` Skip silently on fetch failure.

---

## Context Management Rules

**NEVER read these in the orchestrator (main) context:**
- `references/patterns/*.md` — all 5 pattern files
- `references/analysis-checklist.md`
- `references/heuristics.md`
- `references/adversarial-review.md`
- Any source code files from the target codebase (`*.rs`, `*.go`, `*.cpp`, `*.sol`, etc.)

These are read **only by subagents**. The orchestrator's context budget is reserved for coordination.

**Files the orchestrator MAY read:**
- `references/judging.md` (Stage 5 — dedup and severity validation)
- `references/report-format.md` (Stage 7 — report assembly)
- `references/agents/*.md` (just-in-time, before spawning each agent type)
- `audit/manifest.md` (recon output)
- `audit/progress/*.md` (subsystem checkpoints)
- `audit/findings/*.md` (individual findings as needed for report assembly)
- `audit/metadata.md` (audit parameters)

**Why these rules exist — and the rationalizations to resist:**

On large codebases, context compaction occurs when the orchestrator reads all pattern files and large source files directly. Pattern files get read because more context feels like better routing. Code files get read to "just verify one function." Both are the failure mode — the content stays in context and accumulates until compaction fires.

If you find yourself thinking any of the following — stop, that is the failure mode:
- *"I'll just read this one pattern file to check the routing"* → use the routing table in this prompt
- *"The recon manifest might be wrong, I'll verify by reading the code"* → spawn a targeted subagent hypothesis
- *"This file is only 50 lines, reading it won't hurt"* → it stays in context; every file adds up
- *"Reading analysis-checklist.md will help me write a better agent prompt"* → the hunt agent reads it itself

---

## Pattern Routing Table

Use this table to determine which pattern files to assign to each hunt agent. You never need to read these files — you only need to know which ones are relevant.

| ID | Name | Subsystem Affinity | File |
|----|------|--------------------|------|
| P1 | Input Panic | All entry points | patterns-1 |
| P2 | Batch Errors | Block finalization, batch extrinsics | patterns-1 |
| P3 | EVM Compat | EVM layer, precompiles | patterns-1 |
| P4 | Validator State | Staking, session, consensus hooks | patterns-1 |
| P5 | Vote Dedup | Governance, on-chain voting | patterns-2 |
| P6 | Nondeterminism | Consensus, block production | patterns-2 |
| P7 | RPC Crash | RPC endpoints | patterns-2 |
| P8 | Fee Errors | Fee system, gas metering | patterns-2 |
| P9 | P2P DoS | P2P handlers, mempool | patterns-3 |
| P10 | Bridge Integrity | Cross-chain, bridge handlers | patterns-3 |
| P11 | Unbounded Compute | Block finalization, on_initialize | patterns-3 |
| P12 | ZK Circuits | ZK prover/verifier code | patterns-3 |
| P13 | Charge Order | VM, host-VM bridge, gas | patterns-4 |
| P14 | Replay | Mempool, bridge, admission | patterns-4 |
| P15 | Precision Loss | Rewards, fees, accounting | patterns-4 |
| P16 | Wiring Failures | Module registry, runtime init | patterns-4 |
| P17 | Memory Safety | Unsafe Rust, C/C++, FFI | patterns-5 |
| P18 | Concurrency | Multi-threaded, async shared state | patterns-5 |
| P19 | Undefined Behavior | C/C++ arithmetic, casts | patterns-5 |
| P20 | Serialization | All deserialization paths | patterns-5 |

**Pattern file paths** (for subagent prompts):
```
~/.claude/skills/client-auditor/references/patterns/client-attack-patterns-1.md  → P1-P4
~/.claude/skills/client-auditor/references/patterns/client-attack-patterns-2.md  → P5-P8
~/.claude/skills/client-auditor/references/patterns/client-attack-patterns-3.md  → P9-P12
~/.claude/skills/client-auditor/references/patterns/client-attack-patterns-4.md  → P13-P16
~/.claude/skills/client-auditor/references/patterns/client-attack-patterns-5.md  → P17-P20
```

The recon agent filters pattern applicability and records applicable IDs in the manifest. Read applicable IDs from the manifest in Stage 2 — do not re-evaluate applicability here.

---

## Understanding the Target

### Trust Boundary Model

Prioritize analysis by trust level — lower trust level number = more dangerous, higher priority. This is a default reference ordering; hunt agents may adjust per-project based on recon findings.

1. **Unauthenticated P2P messages** — Any node on the network. No handshake, no stake. Highest risk.
2. **Cross-chain messages** — External chain or bridge as origin. Trust depends on systems you cannot control or audit.
3. **Authenticated peer messages** — Completed handshake, any peer. Low barrier to become a peer.
4. **Transaction processing** — Signed by user, fee-gated. Large attacker population but economically constrained.
5. **Consensus protocol messages** — Validator-only, stake-gated. Small attacker set, high impact when exploited.
6. **RPC endpoints** — Node operators/users. Deployment-dependent exposure; elevate if publicly reachable.
7. **Governance/admin** — Root or governance origin. Smallest attacker population, highest barrier to exploit.

### Entry Point Signatures by Framework

| Concept | Substrate/Rust | Cosmos Go | EL Go | Rust (other) |
|---------|---------------|-----------|-------|-------------|
| Block finalization | `on_finalize`, `execute_block` | `EndBlock`, `FinalizeBlock` | `Finalize`, `Seal` | `process_slot` |
| Tx dispatch | `apply_extrinsic`, `#[pallet::call]` | `DeliverTx`, `CheckTx` | `ApplyTransaction` | `process_transaction` |
| Consensus hooks | `on_initialize`, `on_idle` | `PrepareProposal`, `ProcessProposal` | `VerifyHeader` | `handle_vote` |
| P2P handlers | `handle_protocol_message` | `Receive`, `OnReceive` | `Handle`, `handleMsg` | `handle_gossip` |
| RPC endpoints | `rpc_methods`, `#[rpc]` | `RegisterRoutes`, `NewQuerier` | `RegisterApis` | `register_rpc` |
| Cross-chain | `xcm_execute`, `transact` | `OnRecvPacket` | — | — |

---

## Subagent Prompt Construction

Every agent prompt must include:
- Full text of the agent's instruction file (read just before spawning)
- `skill_dir: ~/.claude/skills/client-auditor/references/`
- `audit_dir: audit/`

Per-agent fields (entry points, pattern files, hypotheses, etc.) are specified in each stage of the Orchestration Flow below.

---

## Orchestration Flow

### Stage 1 — Setup

```bash
mkdir -p audit/findings audit/progress
```

Write `audit/metadata.md`:
```markdown
# Audit Metadata
Target: {target-path}
Date: {today}
Mode: {normal | deep}
Skill version: {VERSION content}
```

### Stage 2 — Reconnaissance

Read `~/.claude/skills/client-auditor/references/agents/recon-agent.md`.

Spawn a recon subagent (Agent tool) with a prompt that includes:
- The full text of `recon-agent.md`
- `target_path: {target-path}`
- `audit_dir: audit/`
- The entry point signatures table from this prompt (copy it in)
- `skill_dir: ~/.claude/skills/client-auditor/references/`

Wait for the subagent to return, then read `audit/manifest.md`.

Extract and hold in context (small structured values only):
- List of subsystem groups with trust levels
- Applicable pattern IDs
- Recommended agent allocation
- Cross-subsystem interaction list

If the manifest contains no subsystem groups, halt immediately: `Audit halted: recon found no entry points in {target-path}. Verify the path is correct and the codebase uses a supported framework (Substrate, Cosmos SDK, geth-fork, or C/C++ node).`

### Stage 3 — Delegated Hunting

Read `~/.claude/skills/client-auditor/references/agents/hunt-agent.md`.

For each subsystem group from the manifest (lowest trust level number first — trust level 1 = unauthenticated P2P = highest priority):

Spawn a hunt subagent with a prompt that includes:
- The full text of `hunt-agent.md`
- `subsystem: {group name}`
- `trust_level: {level from manifest}`
- `entry_points:` [list of file:line:function from the manifest for this subsystem]
- `pattern_files:` [pattern file paths assigned to this subsystem group in the manifest]
- `skill_dir: ~/.claude/skills/client-auditor/references/`
- `audit_dir: audit/`

**You may spawn multiple hunt agents in parallel** if subsystems are independent (no shared entry points). Independent = different files, different trust boundaries, no cross-subsystem calls between them per the manifest.

After each agent returns, record its summary. Do not read raw code or full agent outputs — read only the structured summary it returns. If a finding sounds suspicious, read that specific `audit/findings/[ID].md` to validate it.

### Stage 4 — Cross-Subsystem Analysis

If `audit/manifest.md` lists cross-subsystem interactions:

Read `~/.claude/skills/client-auditor/references/agents/cross-subsystem-agent.md`.

Spawn a cross-subsystem agent with:
- Full text of `cross-subsystem-agent.md`
- `audit_dir: audit/`
- `hypotheses:` [the cross-subsystem interaction list from manifest]
- `skill_dir: ~/.claude/skills/client-auditor/references/`

### Stage 5 — Dedup and Severity Validation

List `audit/findings/`. If empty, skip to Stage 7.

Read all finding files and `references/judging.md`. Apply these rules in order:

1. **Same function, same bug** — two findings at the same file:line with the same root cause → merge into one, keep highest severity, delete the superseded file.
2. **Same pattern, different entry points** — keep separate, add `shared root cause with [other ID]` to each file.
3. **Cascading dependency** — if finding B requires finding A as a precondition, keep both, add `cascading dependency: [other ID]` to each file.

Then validate every finding's severity against the override rules in `judging.md` (admin cap, trusted-party cap, quorum cap, self-recovering cap, impact ceiling, no-exploit-path cap). Update any finding file whose severity violates an override rule.

### Stage 6 — Adversarial Review (DEEP mode only)

Read `~/.claude/skills/client-auditor/references/agents/adversarial-agent.md`.

For each HIGH or CRITICAL finding (already in context from Stage 5), spawn an adversarial review agent with:
- Full text of `adversarial-agent.md`
- `finding_path: audit/findings/{ID}.md`
- `code_files:` [file paths extracted from the finding's Location and Trigger Scenario fields]
- `skill_dir: ~/.claude/skills/client-auditor/references/`
- `audit_dir: audit/`

### Stage 7 — Report Assembly

Read `references/report-format.md`.

If Stage 5 was skipped (no findings), write a report noting zero findings and include the coverage summary from `audit/progress/*.md`. Skip the rest of this stage.

All finding files are already in context from Stage 5. If Stage 6 (adversarial review) ran, re-read any finding files that were modified to pick up updated severities.

Read all `audit/progress/*.md` for coverage summary.

Write final consolidated report to `audit/report.md`.

---

## Resume Protocol

If context has been compacted and you have lost earlier conversation state, recover from disk:

1. Read `audit/metadata.md` — recover audit parameters (target, mode, date)
2. Read `audit/manifest.md` — recover subsystem map and agent allocation
3. List `audit/progress/` — determine which subsystems are complete
4. List `audit/findings/` — see confirmed findings so far
5. If `audit/report.md` exists → audit finished.
6. Re-read the agent prompt file for the stage you are resuming into before spawning any agents:
   - Resuming Stage 3 → re-read `references/agents/hunt-agent.md`
   - Resuming Stage 4 → re-read `references/agents/cross-subsystem-agent.md`
   - Resuming Stage 6 → re-read `references/agents/adversarial-agent.md`
7. Resume from the first incomplete stage. Stage 5 (dedup) is safe to re-run — it is idempotent.

All state needed to continue is on disk. Do not re-read code or pattern files — delegate to subagents as before.

---

## Operating Principles

**Highest risk first.** Unauthenticated P2P and cross-chain handlers (trust level 1-2) carry the most risk. Spend analysis budget inversely proportional to trust level number — level 1 deserves the most budget, not code volume.

**Honest coverage over false completeness.** Report what was analyzed and what wasn't. Coverage is a description of work done, not a metric to optimize.

**Targeted delegation.** Each hunt agent receives a subsystem territory with specific entry points and relevant patterns. The orchestrator does not re-analyze what it delegates — it trusts the manifest's entry points and the hunt agent's judgment within that scope.

**Findings live on disk.** Every confirmed finding is written to `audit/findings/[ID].md` by the hunt agent that found it. The orchestrator reads findings from disk — never reconstructs them from memory.

**Cross-reference patterns.** If a finding touches multiple pattern families, note all applicable IDs. If two findings share a root cause, note the dependency.

---

## Deep Mode

When `deep` is specified, Stage 6 (adversarial review) runs for all HIGH and CRITICAL findings. The Judge's verdict replaces the initial severity. Also review MEDIUM findings that have a confidence score ≥ 80 in their finding file, or where the finding notes a potential upgrade path to HIGH.

---

## Output

All output lives in `audit/`:
- `audit/metadata.md` — audit parameters
- `audit/manifest.md` — recon output (subsystem map)
- `audit/findings/[ID].md` — individual findings (written by hunt agents, updated in Stage 5 and 6)
- `audit/progress/[subsystem].md` — subsystem checkpoints (written by hunt agents)
- `audit/report.md` — final consolidated report

The user can `ls audit/findings/` at any time to see confirmed findings as the audit progresses.

---

## The Audit Is Not Complete

No audit covers everything. The value is in findings confirmed plus coverage honestly reported.

**What this audit does well:** systematic pattern matching against 20 historical vulnerability families, structured trust-boundary analysis, quantitative resource accounting, heuristic structural suspicion exploration.

**What it may miss:** novel vulnerability classes with no historical precedent, complex multi-step chains spanning many subsystems, business logic bugs specific to this protocol's economic design, timing-dependent bugs requiring dynamic analysis, cryptographic implementation correctness.

If a subagent discovers a vulnerability class not covered by P1-P20, flag it in the report as a candidate for future pattern inclusion.

## VERSION

```

```

## references

```

```

## references/adversarial-review.md

# Adversarial Review Protocol

A structured stress-testing technique for high-severity findings. Three perspectives — Red Team, Blue Team, Judge — challenge a finding to calibrate its severity before final reporting.

Initial severity ratings are systematically biased toward over-severity. This protocol is the most effective calibration tool.

---

## When to Apply

Use adversarial review for findings scored HIGH or above (confidence ≥70). For CRITICAL findings, always apply. For MEDIUM findings, apply when the finding is borderline or the impact assessment is uncertain.

Adversarial review is thorough but expensive. Apply it to the highest-impact qualifying findings. Prioritize findings where severity is most uncertain or impact is highest.

---

## Red Team Perspective

**Goal**: Prove the finding IS exploitable. Maximize the attack's impact.

Questions to answer:

1. **Attack construction** — What is the cheapest, simplest path to trigger this? What attacker capabilities are required (any peer, staked validator, admin, physical access)? Describe the step-by-step attack with specific message types, parameter values, and timing.

2. **Mitigation challenges** — For each claimed defense: read the exact code implementing it. Can it be circumvented (race condition, different entry path, parameter combination that bypasses the check)? Is it actually enforced (compiled in, enabled by default, applies to this code path)? Can it be overwhelmed (rate limit too high, bound too generous, cleanup too slow)?

3. **Quantitative attack model** — Cost to the attacker (resources, time, stake). Damage to the victim (concrete numbers). Cost ratio: attacker_cost / victim_damage. How many attackers need to collude? Detection probability during the attack?

4. **Escalation paths** — Can this be chained with other findings? Does it weaken defenses protecting against other attacks? Can the impact be amplified through repetition?

Conclude with: **EXPLOITABLE**, **PARTIALLY EXPLOITABLE**, or **THEORETICAL** — with a one-paragraph justification citing specific code lines.

---

## Blue Team Perspective

**Goal**: Prove the finding is NOT exploitable, or is less severe than claimed. Protect the codebase's reputation fairly.

Questions to answer:

1. **Defense inventory** — List every existing mitigation, even partial: rate limiting (per-IP, per-peer, per-message-type, global), size bounds, authentication requirements, resource caps, load shedding, cleanup mechanisms. For each, cite the exact code location and explain its effectiveness.

2. **Attack cost analysis** — What must the attacker invest (network connections, stake, time, custom tooling)? What is the detection probability (logs, monitoring, peer reputation)? What are the consequences if detected (disconnection, banning, slashing)?

3. **Environmental constraints** — Does this require non-default configuration? Public exposure of typically-private interfaces? Does the default deployment topology prevent this? Are there operational practices that mitigate it?

4. **Impact reassessment** — Is the claimed impact realistic or worst-case theoretical? What is the actual blast radius (one node, one shard, all nodes)? Is recovery automatic or manual? Can honest nodes route around the damage?

Conclude with: **NOT EXPLOITABLE**, **CONSTRAINED**, or **EXPLOITABLE AS DESCRIBED** — with a one-paragraph justification citing specific code lines.

---

## Judge Perspective

**Goal**: Verify both perspectives against source code. Render a final verdict.

Process:

1. **Verify Red Team claims** — For each factual claim, find the code line that confirms or denies it. Mark: VERIFIED / REFUTED / UNVERIFIABLE. If refuted, explain what the code actually does.

2. **Verify Blue Team claims** — Same process. Defense claims are especially important to verify — a claimed rate limit that doesn't actually exist changes the entire analysis.

3. **Resolve disputes** — For each point where Red and Blue disagree, read the actual code path end-to-end. Determine which interpretation is correct. Cite specific references.

4. **Recalculate severity** — Using verified facts only (not claimed facts), recalculate the confidence score using the judgment criteria. Apply only deductions supported by verified Blue Team claims. Do NOT apply deductions for defenses that were refuted.

5. **Final verdict** — One of:
   - **TRUE**: Exploitable as described. Maintain or increase severity.
   - **PARTIAL**: Exploitable but with significant constraints. Adjust severity.
   - **FALSE**: Not exploitable or by-design behavior. Downgrade to Info or remove.

Include: final severity, final confidence score, one-paragraph reasoning with code references.

---

## Application Notes

- The three perspectives should be applied sequentially by a single analyst (or single agent) so that Blue Team reads Red Team's output and the Judge reads both. Running them separately loses the shared context that makes the protocol effective.
- Red Team and Blue Team must both read the actual source code — not just reason about what the code "probably does."
- The Judge must independently verify factual claims. Trust neither Red nor Blue — trust the code.
- If the Red and Blue perspectives substantially agree, the Judge pass can be brief. If they disagree on facts, the Judge pass is the most important part.

## references/agents

```

```

## references/agents/adversarial-agent.md

# Adversarial Review Agent Instructions

You are the adversarial reviewer for a blockchain security audit. You have been given a confirmed finding to stress-test. Your job is to rigorously challenge the finding's severity and exploitability from three perspectives — Red Team, Blue Team, and Judge — and produce a calibrated final verdict.

---

## Your Inputs

You will receive:
- `finding_path` — path to the finding file (e.g., `audit/findings/p2p-P9-01.md`)
- `code_files` — list of file paths referenced in the finding
- `skill_dir` — path to skill references directory
- `audit_dir` — output directory (e.g., `audit/`)

---

## Setup: Read Your References

Before doing anything else, read:

1. `{skill_dir}/adversarial-review.md` — the full Red/Blue/Judge protocol
2. `{skill_dir}/judging.md` — confidence scoring and severity rules
3. `{finding_path}` — the finding you are reviewing
4. All `code_files` referenced in the finding — read the actual code

---

## Execute the Protocol

Follow the protocol from `adversarial-review.md` exactly. Three sequential perspectives:

### Red Team
Goal: Prove the finding IS exploitable. Push severity UP.
- Construct the most concrete attack scenario possible
- Find additional attack vectors or amplifications not in the original finding
- Challenge every "this would be hard" assumption in the finding

### Blue Team
Goal: Prove the finding is NOT exploitable (or less severe). Push severity DOWN.
- Find existing defenses the original analysis may have missed
- Identify constraints that limit the attacker population or attack window
- Check whether the broken invariant actually leads to the claimed impact

### Judge
Goal: Calibrate severity based on both perspectives.
- Weigh Red Team's concrete attack paths against Blue Team's defenses
- Apply override rules from `judging.md` (admin cap, quorum cap, self-recovering cap, etc.)
- Produce a final verdict: severity, confidence, and 1-2 sentence rationale

---

## Output

Update the finding file at `{finding_path}` by appending an adversarial review section using this exact format (matches the report summary table):

```markdown
---

## Adversarial Review

| Role | Verdict | Key Argument |
|------|---------|--------------|
| Red Team | [EXPLOITABLE / PARTIALLY EXPLOITABLE / THEORETICAL] | [strongest attack scenario or amplification found] |
| Blue Team | [NOT EXPLOITABLE / CONSTRAINED / EXPLOITABLE AS DESCRIBED] | [strongest defense found, or "no sufficient mitigation"] |
| **Judge** | **[TRUE / PARTIAL / FALSE]** | [calibrated reasoning with file:line refs; apply override rules from judging.md] |

**Final severity:** [severity] (was: [original severity])
```

If the severity changes, also update the `**Severity:**` field at the top of the finding.

---

## Return to Orchestrator

```
Adversarial review complete: {finding_id}
Original severity: [X]
Final severity: [Y]
Change: [upgraded | downgraded | unchanged]
Rationale: [one sentence]
```

## references/agents/cross-subsystem-agent.md

# Cross-Subsystem Analysis Agent Instructions

You are a specialist agent for tracing security issues at subsystem boundaries. Individual hunt agents analyzed each subsystem in isolation. Your job is to find bugs that only appear when two subsystems interact — trust level mismatches, shared state races, data flow issues at boundary crossings.

---

## Your Inputs

You will receive:
- `audit_dir` — output directory (e.g., `audit/`)
- `hypotheses` — specific cross-boundary interactions to investigate (list of: caller file:line → callee module)
- `skill_dir` — path to skill references directory

---

## Setup: Read Your References

1. `{audit_dir}/manifest.md` — understand the subsystem map and trust boundary levels
2. `{skill_dir}/heuristics.md` — focus on the "Cross-Subsystem Interactions" and "Asymmetric Trust" sections
3. `{skill_dir}/analysis-checklist.md` — focus on "Zero-Trust Message Check" and "Data Lifetime"
4. `{skill_dir}/judging.md` — for scoring any findings
5. `{skill_dir}/report-format.md` — finding template (required for writing findings to disk)
6. `{audit_dir}/findings/*.md` — read confirmed findings to understand what has already been found
7. `{audit_dir}/progress/*.md` — read hunt agent progress checkpoints for cross-subsystem call observations

---

## What to Investigate

For each provided hypothesis (caller:line → callee):

1. **Read the call site code** — what data crosses the boundary? What trust level does it carry?
2. **Read the callee code** — what does it assume about its inputs? Does it validate them?
3. **Check the trust mismatch** — if caller is trust level 1 (unauthenticated P2P) and callee assumes validated input, that's the bug.
4. **Check shared state** — does the caller modify state that the callee reads without synchronization or ordering guarantees?
5. **Apply the cross-subsystem heuristics from heuristics.md** — cross-subsystem caller assumptions, asymmetric trust, implicit global state.

Also look for patterns the individual hunt agents may have flagged in their progress checkpoints but not analyzed (cross-subsystem call observations).

---

## Finding Validation

Same 3-check FP gate as hunt agents:
1. Concrete execution path with file:line references
2. Externally reachable (can an attacker trigger the cross-boundary call?)
3. No sufficient existing defense

---

## Output

For each confirmed finding, write `{audit_dir}/findings/[ID].md` immediately. Use the prefix `xsub-` for all finding IDs: `xsub-P[N]-[NN]` or `xsub-HEURISTIC-[NN]`.

Use the finding template from `{skill_dir}/report-format.md`. The finding title should clearly indicate the cross-subsystem nature: e.g., "P2P Input Bypasses Validation in Shared Serialization Layer."

---

## Return to Orchestrator

```
Cross-subsystem analysis complete.
Hypotheses investigated: N
Findings: N total — [N Critical, N High, N Medium, N Low, N Informational]
Finding IDs: [list]
Hypotheses cleared (no issue): [brief list]
```

## references/agents/hunt-agent.md

# Hunt Agent Instructions

You are a security analyst for a blockchain client audit. You have been assigned one or more subsystems to analyze. Your job is to find real vulnerabilities — bugs an attacker can exploit to halt, fork, or steal from the network.

You will read pattern files, methodology references, and code from disk. You write findings to disk as you confirm them. You do not summarize code; you find bugs.

---

## Your Inputs

You will receive:
- `subsystem` — name(s) of the subsystem(s) you are analyzing
- `trust_level` — trust boundary level for your entry points (1=unauthenticated P2P, 7=governance/admin)
- `entry_points` — list of file:line:function to analyze
- `pattern_files` — paths to the pattern files relevant to your subsystem
- `skill_dir` — path to the skill's references directory (e.g., `~/.claude/skills/client-auditor/references/`)
- `audit_dir` — output directory (e.g., `audit/`)

---

## Setup: Read Your References

Before analyzing any code, read these files from disk:

1. All assigned `pattern_files` (e.g., `{skill_dir}/patterns/client-attack-patterns-1.md`)
2. `{skill_dir}/analysis-checklist.md`
3. `{skill_dir}/heuristics.md`
4. `{skill_dir}/judging.md`
5. `{skill_dir}/report-format.md`

These are your working knowledge. Read them fully before touching the codebase.

---

## How to Analyze Code

Start from trust boundaries. The question is not "what does this module do?" but "what can an attacker make this module do?"

**Explore freely.** The handbook materials you read in Setup — patterns, analysis checklist, heuristics — are references to consult when relevant, not a mandatory pipeline to execute in order. Follow your judgment: read what you need, dig where it looks interesting, stop when you're confident.

Some questions worth keeping in mind as you explore:

- **What can an attacker control?** Every field in an incoming message, every RPC parameter, every byte in a serialized transaction.
- **Where does the data go?** Follow it through state modifications, queues, databases. What bounds exist? When is it cleaned up?
- **What defenses exist?** Read them — don't assume they're there because they should be.
- **Does anything match the pattern families you read?** Be concrete — cite file:line.
- **Be quantitative.** "Could allocate memory" is not a finding. "4 KB × 100 msg/s × 300 s = 120 MB per peer, 1000 peers = 120 GB" is.
- **When you find something, look nearby.** Vulnerabilities cluster.

**Do not trust complexity as a signal of safety.** Short, simple-looking handlers invite the assumption that they're harmless — and are therefore more dangerous.

---

## Finding Validation: 3-Check FP Gate

Before reporting any finding, all three checks must pass. If any fails, discard the finding.

**Check 1 — Concrete execution path**
- There is a traceable path from attacker input → invariant break
- Each step cites file:line
- No dead code or disabled features in the path

**Check 2 — Externally reachable entry point**
- The path starts from a real entry point (P2P, RPC, tx, XCM, etc.)
- No validator-only or localhost-only assumption unless that's the trust level

**Check 3 — No sufficient existing defense**
- Read the actual defense (don't assume it exists)
- Size limits, rate limiting, authentication, existing checks — verify they don't already prevent the exploit

If all three pass, consult `judging.md` for confidence scoring and severity classification. Apply all override rules.

---

## Writing Findings

**Write each confirmed finding immediately** — do not accumulate in memory.

Use `{audit_dir}/findings/[ID].md` where ID follows the pattern `{subsystem}-P[N]-[NN]` or `{subsystem}-HEURISTIC-[NN]`. The subsystem prefix prevents ID collisions when multiple hunt agents run in parallel.

Use `{subsystem}-P[N]-[NN]` when the finding matches a known pattern family (P1-P20). Use `{subsystem}-HEURISTIC-[NN]` when the bug class does not map to any existing pattern.

Use the finding template from `report-format.md`. Each finding must include:
- ID, severity, confidence, pattern(s)
- File:line location
- Concrete code excerpt showing the issue
- Impact assessment (quantitative where possible)
- Recommendation

After writing a finding, note its ID in your progress checkpoint.

---

## Progress Checkpointing

After completing each entry point group (or every 3-5 entry points), write:

`{audit_dir}/progress/{subsystem}.md`

```markdown
# Progress: {subsystem}

Status: in-progress | complete
Entry points analyzed: [list]
Entry points remaining: [list]
Findings written: [IDs]
Notes: [cross-subsystem calls noticed, patterns checked, anything unusual]
```

Update this file as you go. If your context is interrupted, this file lets the orchestrator recover your state.

---

## Cross-Subsystem Notes

When you encounter a call into a different subsystem (e.g., a transaction handler calling a shared oracle, a P2P handler calling serialization), **do not analyze the callee subsystem** — that is another agent's territory. Instead, record the observation in your progress checkpoint:

```
Cross-subsystem call: {this file:line} → {callee module/function}
Trust level at call site: {your trust level}
Potential concern: [brief note, e.g., "untrusted input passes into shared codec"]
```

The orchestrator will decide whether to spawn a cross-subsystem agent to trace this.

---

## Return to Orchestrator

After completing all assigned entry points, return this summary (concise):

```
Hunt complete: {subsystem}
Entry points analyzed: N
Findings: N total — [N Critical, N High, N Medium, N Low, N Informational]
Finding IDs: [list]
Coverage: [what was analyzed, what was skipped and why]
Cross-subsystem observations: [any noted above]
Progress checkpoint: {audit_dir}/progress/{subsystem}.md
```

Do not reproduce finding content in your return message — the orchestrator reads findings from disk.

## references/agents/recon-agent.md

# Recon Agent Instructions

You are the reconnaissance agent for a blockchain client security audit. Your job is to explore the target codebase, map its attack surface, and write a structured manifest that hunt agents will use to do deep analysis. You read code; you do not audit it.

---

## Your Inputs

You will receive:
- `target_path` — root of the codebase to explore
- `audit_dir` — where to write output (`audit/manifest.md`)
- `skill_dir` — path to skill references directory
- The entry point signature table (below, for searching)

---

## Entry Point Signatures to Search For

Search for these patterns across the codebase. When found, record file, line number, function name.

| Framework | Patterns to grep |
|-----------|-----------------|
| Substrate/Rust | `fn on_initialize`, `fn on_finalize`, `fn apply_extrinsic`, `fn execute_block`, `fn on_idle`, `fn on_offchain_worker`, `#\[pallet::call\]`, `fn handle_`, `rpc_methods`, `register_rpc`, `fn validate_unsigned`, `fn pre_dispatch` |
| Go (Cosmos SDK) | `EndBlock`, `BeginBlock`, `FinalizeBlock`, `DeliverTx`, `CheckTx`, `PrepareProposal`, `ProcessProposal`, `RegisterRoutes`, `NewQuerier`, `Receive`, `OnReceive` |
| Go (execution client) | `Handle`, `handleMsg`, `ApplyTransaction`, `Finalize`, `Seal`, `VerifyHeader`, `RegisterApis` |
| C/C++ | `processLedger`, `doApply`, `onConsensus`, `handleMessage`, `onMessage`, `handler`, `doCommand` |
| Universal | `unsafe`, `unwrap()`, `panic!`, `unreachable!`, `expect(`, `todo!`, `unimplemented!` |

Also look for: message type enum + handler dispatch switches, protocol buffer service definitions, bridge/cross-layer message processing, XCM/IBC handlers, precompile dispatch tables.

---

## What to Explore

### Step 1 — Codebase Structure

```
- What languages are used? (Rust, Go, C++, Solidity)
- What framework? (Substrate/Cumulus, Cosmos SDK, geth-fork, custom)
- Rough size: total files, rough line count (find . -name "*.rs" | wc -l style)
- Top-level directory structure (pallets/, runtime/, precompiles/, node/, etc.)
```

### Step 2 — Entry Point Discovery

Run targeted greps for each entry point signature. For each match:
- Record: file path, line number, function name
- Classify trust boundary level:
  1. Unauthenticated P2P (any peer can trigger, no handshake)
  2. Cross-chain (bridge or cross-chain messaging — external chain as trust root)
  3. Authenticated peer (completed handshake, not trusted)
  4. Transaction (signed, fee-gated)
  5. Consensus (validator-only, stake-gated)
  6. RPC (operator/user-facing — elevate if public-facing)
  7. Governance/admin (root or governance origin)

### Step 3 — Pattern Applicability Filter

For each of P1-P20, determine if it applies to this codebase:

| ID | Applies if... |
|----|--------------|
| P1 | Always |
| P2 | Always |
| P3 | EVM compatibility layer exists (pallet-evm, pallet-ethereum, Frontier, geth-fork) |
| P4 | Validator set management code exists |
| P5 | On-chain voting or quorum counting exists |
| P6 | Always (consensus paths) |
| P7 | RPC endpoints exist |
| P8 | Complex fee system (dynamic fees, gas metering, fee markets) |
| P9 | P2P message handlers exist |
| P10 | Bridge, XCM, IBC, cross-chain messaging exists |
| P11 | Always (block finalization hooks) |
| P12 | ZK prover/verifier code exists |
| P13 | VM, host function dispatch, or gas-charged operations exist |
| P14 | Always (mempool, state transitions) |
| P15 | Reward calculations, fee distributions, or financial accounting exist |
| P16 | Module registration, plugin system, or runtime configuration exists |
| P17 | `unsafe` Rust blocks, C/C++, FFI boundaries exist |
| P18 | Multi-threaded code, async with shared state, or concurrent access patterns |
| P19 | C/C++ arithmetic, casts, or platform-dependent math |
| P20 | Always (any deserialization) |

### Step 4 — Subsystem Grouping

Group entry points into subsystems based on trust boundary and functional area. Typical groups:

- **p2p**: Unauthenticated/authenticated peer message handlers
- **transactions**: Transaction validation and processing (CheckTx, apply_extrinsic, validate_unsigned)
- **consensus**: Validator-only hooks, block production, finalization
- **rpc**: RPC endpoint handlers
- **evm**: EVM precompiles, pallet-ethereum, pallet-evm (if present)
- **bridge_xcm**: XCM/IBC handlers, cross-chain message processing
- **staking_rewards**: Financial logic — staking, rewards, inflation
- **admin**: Root/governance-origin extrinsics

For small codebases (< 5K lines): 2-3 groups.
For medium codebases (5K-30K lines): 3-5 groups.
For large codebases (> 30K lines): 4-7 groups.

Also recommend which pattern files each hunt agent should receive:
- `client-attack-patterns-1.md` → P1, P2, P3, P4
- `client-attack-patterns-2.md` → P5, P6, P7, P8
- `client-attack-patterns-3.md` → P9, P10, P11, P12
- `client-attack-patterns-4.md` → P13, P14, P15, P16
- `client-attack-patterns-5.md` → P17, P18, P19, P20

Each subsystem should receive only the pattern files for patterns that are both applicable AND relevant to that subsystem's trust boundary.

### Step 5 — Cross-Subsystem Interactions

Identify places where one subsystem calls into another. Look for:
- P2P handler → shared serialization/state
- RPC handler → consensus/mempool state
- Transaction processor → external oracle/precompile
- XCM/bridge handler → local state modification

For each, note: caller subsystem, callee subsystem, file:line of the call site.

---

## Output Format

Write `{audit_dir}/manifest.md` with exactly this structure:

```markdown
# Audit Manifest

## Codebase Overview
- Language(s): ...
- Framework: ...
- Size: ~N files, ~N lines
- Notable: [any unusual architecture, dual-runtime, multi-chain, etc.]

## Applicable Patterns
Applicable: P1, P2, P3, ... [list IDs]
Not applicable: P4 (no local validator set), P12 (no ZK), ... [list with reason]

## Entry Points
| Subsystem | Trust Level | File | Line | Function |
|-----------|-------------|------|------|----------|
| transactions | 3 | pallets/foo/src/lib.rs | 142 | apply_extrinsic |
| ... | ... | ... | ... | ... |

## Subsystem Groups
### Group 1: [name]
Trust level: [N]
Entry points: [list from table above]
Pattern files: [which client-attack-patterns-N.md files]
Priority: [high/medium/low based on trust level and code volume]

### Group 2: [name]
...

## Cross-Subsystem Interactions
| From | To | File | Line | Notes |
|------|----|------|------|-------|
| p2p | serialization | src/net/handler.rs | 88 | untrusted input enters shared codec |
| ... | ... | ... | ... | ... |

## Agent Allocation
Recommended: N hunt agents
- Agent 1: [group names] — Priority: high
- Agent 2: [group names] — Priority: medium
...
```

---

## Return to Orchestrator

After writing the manifest, return this summary (concise, no code):

```
Recon complete.
Codebase: [language/framework], ~N lines
Subsystems found: N ([list names])
Applicable patterns: [P-IDs]
Recommended hunt agents: N
Manifest written to: {audit_dir}/manifest.md
Cross-subsystem interactions: N found ([brief descriptions if any])
```

## references/analysis-checklist.md

# Analysis Checklist

Seven lenses to apply when analyzing code at a trust boundary. These are questions to ask, not steps to execute in order — apply whichever are relevant to the code you're reading.

---

## 1. Branch Exhaustion

For every branch in the handler (if/else, switch/case, ternary, early return, loop condition):

- What does an attacker control at this branch point?
- What state does this branch modify?
- What happens on the path NOT taken — does the else/default/fallthrough have the same protections as the primary path?
- Have you read every branch, or are you assuming some are safe without checking?

The goal is completeness: a confirmed high-severity vulnerability was missed because the auditor skipped the else branch of a handler deemed "simple." Don't mark any branch as harmless without applying the other six lenses to it.

---

## 2. Zero-Trust Message Check

For messages and requests arriving from external sources:

- Can this message arrive WITHOUT the local node requesting it? (unsolicited message)
- If yes: what state does the handler modify for unsolicited messages?
- Is there correlation between a prior outbound request and this inbound message? (request ID, sequence number, pending-set check)
- Does the handler distinguish "I asked for this" from "peer just sent it"?
- What happens if an attacker sends 10,000 of these per second with no prior interaction?

Unsolicited message paths are the highest-risk surface — any peer can trigger them at will.

---

## 3. Data Lifetime Trace

For each data structure written by the handler:

- **Where** does the data go after this handler returns? (in-memory cache, database, queue, global map)
- **What bounds** exist on the data structure's size? (max entries, max bytes, per-peer isolation)
- **When** is data removed? (TTL, LRU eviction, explicit cleanup, never)
- **Injection rate**: how fast can an attacker add data? (messages/sec × data/message)
- **Cleanup rate**: how fast is data removed under normal operation? (items/sec, time between cleanup passes)
- If injection_rate > cleanup_rate, how long until resource exhaustion?

Data that enters the system but never leaves is a resource exhaustion vector.

---

## 4. Quantitative Resource Accounting

For each resource-consuming operation, compute concrete numbers:

- **Cost per unit**: bytes / reads / cycles per item processed
- **Units per message**: packet_size / unit_size, or loop iteration bound
- **Rate limit**: messages/sec allowed, credit system, per-IP limit
- **Total consumption**: units_per_msg × cost_per_unit × msgs_before_disconnect
- **System capacity**: available memory, disk IOPS, CPU budget
- **Time to impact**: total_consumption / system_capacity

Timeline calibration: seconds = critical, minutes = high, hours = medium, days = low.

"Could allocate memory" is not a finding. "Allocates 4 KB per message × 100 messages/sec × 300 sec before disconnect = 120 MB per peer, 1000 peers = 120 GB" is a finding.

---

## 5. Missing-Defense Inventory

Before analyzing what the code DOES, check what it SHOULD do. For each handler at a trust boundary, check whether these defenses are present:

- [ ] **Input size validation** — message size, array length, field count
- [ ] **Request correlation** — is this a reply to something we asked for?
- [ ] **Per-peer resource isolation** — separate quotas/caches per peer
- [ ] **Rate limiting** — specific to this message type's cost, not just connection-level
- [ ] **Verify-before-store** — validate data before caching/persisting
- [ ] **Resource cap** — hard limit on the destination data structure
- [ ] **Load shedding** — overload detection and graceful degradation
- [ ] **Cleanup/eviction** — mechanism for removing stored data

For each: mark PRESENT (with code reference) or ABSENT. A handler with no bugs but also no defenses is still a finding — absent defenses are the vulnerability.

---

## 6. Thread Safety

*Apply only to multi-threaded clients. Skip for single-threaded runtimes.*

For each shared data structure accessed by the handler:

- Is this handler called from a single thread or multiple threads?
- What lock protects the shared state? Is it held for the entire read-modify-write sequence?
- Is there a TOCTOU gap between checking a condition and acting on it?
- Can another thread modify the data structure between this handler's read and write?
- What is the lock acquisition order? Can this handler deadlock with another code path?

---

## 7. Memory Safety

*Apply only to C/C++ and unsafe Rust. Skip for memory-managed languages.*

For each pointer, reference, or buffer operation in the handler:

- Who owns the memory being accessed? Can the owner free it while this handler runs?
- Are array/buffer accesses bounds-checked before use?
- Do any integer calculations determine allocation sizes or offsets? Can they overflow?
- For C++ iterators: can the underlying container be modified while iteration is in progress?
- For FFI boundaries: who is responsible for freeing allocated memory? Is the contract documented and enforced?

## references/heuristics.md

# Heuristic Strategies

Strategies for finding vulnerabilities that patterns alone won't catch. These are signals that warrant deeper investigation — places where bugs hide even when no specific pattern applies.

---

## Structural Suspicion

Code structure itself reveals risk. Look for:

- **State machines without explicit invariant enforcement** — code that handles state transitions without making the valid states and transitions explicit. Where does this state machine actually enforce its invariants? Can an attacker force a transition that skips validation or reset the machine to replay a transition?
- **Cross-subsystem caller assumptions** — a function that assumes its caller has validated input, but is called from a new context where validation is skipped. Grep for the function's callers — if any caller skips validation the function expects, that's a finding.
- **Asymmetric trust** — code that trusts local state but accepts peer-supplied values that override it. A function validates parameters when called from RPC but not when called from P2P — same logic, different trust assumptions.
- **Error path divergence** — the happy path is well-tested; the error/recovery path is not. Error handlers that attempt partial rollback, retry, or fallback often contain state corruption bugs.
- **Copy-paste with subtle differences** — two handlers that look almost identical but differ in one check or one field. The difference is either intentional (document why) or a bug.

---

## Complexity Signals

Complexity doesn't mean "vulnerable," but it correlates with unexamined assumptions:

- **Functions significantly longer or more branchy than their neighbors** — complexity without a good reason is often where bugs hide. Apply branch exhaustion with extra care.
- **Reimplemented standard functionality** — code that re-implements something the standard library already provides (custom parsers, custom encoders, custom hash maps). Reimplementations frequently have subtle off-by-one or boundary condition errors.
- **Multiple layers of indirection before security decisions** — permissions checks buried 4 calls deep, validation separated from the code that relies on it by several layers of abstraction.
- **Protocol negotiation and version handling** — code that switches behavior based on protocol version or feature flags. Each combination is a separate attack surface.
- **Recursive or re-entrant paths** — functions that can be re-entered before previous invocations complete. Even without explicit recursion, message handlers that dispatch new messages can create re-entrancy.
- **Type conversion chains** — data that passes through multiple serialization/deserialization steps. Each step can lose information, change semantics, or introduce inconsistency.

---

## Temporal Assumptions

Bugs that depend on timing or ordering:

- **Assumed message ordering** — handler assumes message A arrives before message B. What if B arrives first, or A never arrives? What if an attacker interleaves messages from multiple connections?
- **Time-of-check to time-of-use (TOCTOU)** — a condition is checked, then acted upon later. Between check and use, can an attacker (or another thread/async task) change the state?
- **Initialization dependencies** — code that relies on external setup having already happened. What if it hasn't? What if initialization is re-run while the system is already operating?
- **Timeout and expiry interactions** — what happens when a timeout fires during an in-progress operation? Does the timeout handler conflict with the operation handler?
- **Epoch and round transitions** — consensus code that assumes operations complete within a single epoch/round. What if the epoch advances mid-operation?
- **Cleanup that can be skipped** — early returns before cleanup, panic recovery that drops cleanup, error paths that skip resource release.

---

## Cross-Boundary Data Flow

Data that crosses trust boundaries deserves scrutiny at every crossing:

- **Serialization boundaries** — data entering or leaving the node (network, disk, RPC). Every field in a serialized message is attacker-controlled until validated. Deserialization libraries validate format, not meaning.
- **Subsystem boundaries** — data passed between internal components (e.g., P2P layer hands data to consensus layer). Each subsystem may assume the other validated the data. Check: who actually validates?
- **Privilege boundaries** — data from an unprivileged context used in a privileged operation. Even if the data was valid when received, has it been modified between receipt and use?
- **Aggregation of peer-supplied values** — vote weights, fee estimates, block hashes. The aggregation itself can be the vulnerability even if individual inputs are valid (e.g., overflow in summation, quorum miscounting).
- **Values validated at ingress but used later** — data validated on receipt, then passed through several functions. Could it be mutated in between? Could the validation become stale?

---

## Cross-Subsystem Interactions

These are uniquely valuable because no single-subsystem analysis can find them:

- **Functions that bridge two subsystems** — a P2P handler calling a shared serialization function, an RPC handler triggering consensus logic, a transaction processor accessing the networking layer.
- **Data structures shared across subsystem boundaries** — without clear ownership contracts. Who is responsible for invariant enforcement? Who cleans up?
- **Trust level mismatches** — code in a lower-trust subsystem (e.g., P2P) calling into a higher-trust subsystem (e.g., consensus) without re-validation at the boundary.

---

## Implicit Global State

Hidden shared state is where race conditions, resource exhaustion, and state corruption live:

- **Global maps and caches without bounds** — in-memory data structures that grow based on external input. Grep for global/static maps, then check: is there a size limit? Is there eviction? Can an attacker fill it?
- **Reference counting and shared ownership** — objects with multiple owners. Can one owner free/invalidate while another is using? Especially dangerous in C++ with `shared_ptr` across threads.
- **Metrics and counters** — counters that grow without bound, especially those used in allocation decisions or comparisons. An attacker who can increment a counter to overflow can invert a comparison.
- **Configuration state assumed immutable** — code that reads config once and assumes it doesn't change. If config can be updated at runtime (hot reload, admin RPC), cached config values may diverge from reality.
- **Connection and peer state** — per-peer state stored in global structures. If peer disconnection doesn't clean up all state, reconnection can interact with stale state from the previous session.

## references/judging.md

# Finding Judgment Criteria

This document defines the false-positive gate and confidence scoring system used to evaluate findings from the pattern scan agents. Every finding must pass the FP gate before being scored, and every scored finding receives a severity classification.

---

## 3-Check False Positive Gate

All three checks must pass. If any check fails, the finding is classified as FALSE POSITIVE and excluded from the report.

### Check 1: Concrete Execution Path

There must be a concrete, traceable execution path from attacker-controlled input to the invariant break.

**Pass criteria:**
- The path can be described as a sequence of function calls with specific file:line references
- Each step in the path is reachable from the previous step (no dead code, no disabled features)
- The attacker input that enters the path is specified (message type, RPC method, tx field, etc.)

**Fail indicators:**
- Path requires calling internal-only functions not reachable from any entry point
- Path traverses code gated by compile-time flags that are off in production
- Path requires state that cannot be constructed through any external interface

### Check 2: External Reachability

The entry point must be reachable by an external actor (peer, RPC caller, transaction submitter), not only by internal code paths.

**Pass criteria:**
- The entry point is a P2P message handler, RPC endpoint, transaction processor, or consensus hook
- The entry point can be reached without admin/operator credentials (or the finding explicitly notes the admin requirement)
- The network path from attacker to entry point is specified

**Fail indicators:**
- Handler is only called from internal timers or maintenance routines
- Entry point requires localhost access AND default config binds to localhost
- Function is a test helper or debug-only path compiled out of release builds

### Check 3: No Sufficient Existing Guard

No existing defense mechanism is sufficient to fully prevent the attack.

**Pass criteria:**
- Each claimed mitigation has been checked against the actual code
- Mitigations are demonstrably insufficient (rate limit too high, size check on wrong field, etc.)
- The finding survives layered defense analysis (all mitigations considered in combination)

**Fail indicators:**
- An existing check already validates the exact input that triggers the bug
- Rate limiting reduces the attack below the impact threshold
- The resource is bounded and the bound is enforced before the expensive operation

---

## Confidence Scoring

Start at 100 and apply deductions. Multiple deductions stack.

| Condition | Deduction | Rationale |
|-----------|-----------|-----------|
| Requires admin/operator privileges | -30 | Drastically narrows attacker population |
| Requires compromise of a hardened trusted-party key (guardian, validator, committee member, authorized signing key) | -40 | Prerequisite compromise constitutes a more severe independent incident; secondary effects do not meaningfully elevate risk above that baseline |
| Requires >33% Byzantine validators | -25 | Above standard BFT security assumption |
| Requires ≥ consensus quorum of compromised parties | -80 | Attacker already owns the protocol; secondary bugs are subsumed by the primary compromise |
| Requires non-default configuration | -20 | Most deployments unaffected |
| Feature gated behind activation flag, governance vote, or hard fork not yet deployed | -15 | Not currently exploitable in production |
| Impact is self-contained (attacker only harms themselves) | -15 | No externality to other users |
| Existing partial mitigation present | -10 | Reduces but does not eliminate risk |
| Requires sustained attack >1 hour (not applicable to instant-trigger bugs such as memory corruption or logic errors) | -10 | Increases detection probability |
| Input rejected by deserialization before reaching vulnerable code | -40 | Strong structural defense |
| No current exploit path exists — condition is unreachable in all present code paths | -50 | Latent/future risk only |

### Scoring examples

**Example A — High confidence:**
- Start: 100
- No admin required: 0
- Default configuration: 0
- Active feature: 0
- Partial mitigation (connection-level rate limit): -10
- Attack completes in minutes: 0
- **Final: 90 → HIGH**

**Example B — Low confidence:**
- Start: 100
- Requires admin privileges: -30
- Requires non-default config to expose: -20
- Self-contained impact: -15
- Existing input validation catches most cases: -10
- **Final: 25 → LOW**

---

## Severity Classification

| Severity | Criteria | Confidence Range |
|----------|----------|-----------------|
| **Critical** | Chain halt, chain split, or direct fund loss achievable by any peer/user | ≥80 AND impact is chain-wide or financial |
| **High** | Node DoS from any peer, significant state corruption, or bypass of core security mechanism | ≥70 |
| **Medium** | Requires non-default configuration, or causes degradation without full DoS, or has significant partial mitigations | 40-69 |
| **Low** | Theoretical with significant practical constraints, or requires unlikely preconditions | 20-39 |
| **Informational** | Design observation, defense-in-depth suggestion, or by-design behavior that warrants documentation | <20 |

### Severity override rules

1. **Never promote above the impact ceiling:** A finding that can only crash one node cannot be Critical, regardless of confidence.
2. **Downgrade for design intent:** If the behavior is explicitly documented as a design trade-off with formal analysis, cap at Informational.
3. **Upgrade for chain-wide impact:** If a Medium-confidence finding can cause chain halt or fund loss, it stays at Medium (not Low) — the impact justifies the attention even with uncertainty.
4. **Admin-only findings cap at Medium:** Findings requiring admin credentials are capped at Medium severity regardless of impact, unless the admin interface itself is the finding (e.g., admin credentials exposed).
5. **Trusted-party key compromise cap at Low (with system-wide exception):** Findings whose only exploit path requires compromise of a hardened trusted-party key (guardian key, validator key, committee member key, authorized signing key) are capped at **Low** by default. The key compromise itself is the high-severity incident; the secondary effect described in the finding does not independently elevate risk beyond that baseline. **Exception — upgrade to Medium** if a single compromised party can affect the entire system (e.g., corrupt shared global state, force a chain halt, block quorum for all honest participants, or produce an incorrect result visible to all consumers) rather than only degrading one local node. The test is whether the blast radius is system-wide or node-local: node-local → Low; system-wide with one compromised key → Medium.
6. **No current exploit path cap at Low / Informational:** Findings with no reachable exploit path in the current codebase (e.g., all existing code paths return an error before the vulnerable condition is reached, making the bug latent rather than active) are capped at **Low**. If the only risk is future code changes introducing the exploit path, cap at **Informational**.
7. **Self-recovering resource exhaustion cap at Medium:** Findings that (a) only increase resource consumption (CPU, memory, bandwidth, channel fill) without causing a crash, data loss, or correctness failure, AND (b) where the system returns to baseline automatically when the attack stops (e.g., via TTL expiry, channel backpressure, timeout, or GC), are capped at **Medium** regardless of confidence. "Self-recovering" means no operator intervention is required to restore normal operation after the attack ceases.
8. **Quorum-required exploit cap at Informational:** Findings whose exploit path requires compromising a number of parties equal to or greater than the system's consensus quorum threshold are capped at **Informational**. At quorum compromise, the attacker already has full control of the protocol — they can forge any message, update the validator/guardian set, and execute arbitrary governance actions. Any secondary bug exploitable only at quorum level does not independently elevate risk; it is subsumed by the catastrophic primary compromise. Report as a defense-in-depth observation only.

---

## Deduplication Rules

When multiple findings share the same root cause:

1. **Same function, same bug:** Merge into one finding. Use the highest severity.
2. **Same pattern, different entry points:** Keep separate but note the shared root cause. The fixing recommendation should address the root cause, not each instance.
3. **Cascading effects:** If Finding A enables Finding B, report both but note the dependency. If fixing A eliminates B, note that B is contingent.

## references/patterns

```

```

## references/patterns/client-attack-patterns-1.md

# Client Attack Patterns 1-4

Pattern families extracted from historical blockchain client vulnerabilities across 20+ ecosystems. Mechanism descriptions are preserved for pattern matching.

---

## P1. Negative / Illegal Input Amount Triggers Unrecoverable Panic

**Broken invariant**
Externally influenced values must be normalized before they reach panic-only constructors or fatal framework return paths.

**Attacker input surface**
User messages, queued deferred-processing work items, validator votes, and framework callbacks that forward untrusted numeric or enum-like values.

**Trigger condition**
A malformed value survives admission checks and hits a path that treats invalid input as a programmer error rather than a recoverable user error.

**State-transition path**
External input → decode or queue → consensus-path replay → panic/assert/fatal error return → block or process abort.

**Impact envelope**
Consensus-path variants halt the chain; node-path variants crash the local process until the triggering item is filtered or state is repaired.

**False-positive signal:** the value is clamped or converted to a normal error before the fatal sink is reached.

**Recurring disguises / variants**
- Negative balances or stake removals
- Illegal gas or size values that violate framework assumptions
- Framework-level handlers returning a fatal error when they only meant to reject a vote
- Deferred processing paths re-consuming user data without re-validating

**Audit questions**
- Which constructors, helper APIs, or framework return combinations can panic on invalid values?
- Can deferred processing paths re-consume user data without re-validating it at the final sink?
- Does the code confuse soft rejection with fatal execution failure?

**Attack surfaces to investigate**

- **Deferred re-validation gap:** User-submitted values (negative amounts, zero denominators, out-of-range enums) that pass initial admission but reach a panic-prone constructor in a deferred block-finalization or consensus-replay path without being re-validated.
- **Framework error contract mismatch:** Code paths where returning a certain error status (e.g., non-nil error with rejection) is treated as a fatal abort by the framework rather than a soft rejection — no forged signature needed, just the wrong return shape.
- **State-shaping into illegal conditions:** Attacker manipulates on-chain state (e.g., balances, stakes, governance parameters) so that block-finalization logic encounters a value the fatal-path constructor cannot handle, escalating a localized state anomaly into a chain halt.

---

## P2. Error Handling Defect in Batch Processing Loops

**Broken invariant**
One malformed item in a batch must not poison processing of all remaining valid items.

**Attacker input surface**
Loops over validators, votes, queued requests, or accounting entries in block finalization, proposal processing, and governance workflows.

**Trigger condition**
A single item returns an error and loop control, cleanup, or state updates are handled asymmetrically.

**State-transition path**
Batch iteration → one element faults → break / partial update / swallowed error → later items skipped or state diverges.

**Impact envelope**
The result ranges from chain halt to silent selection bias, wrong vote tallies, or persistent accounting drift.

**False-positive signal:** the loop is intentionally all-or-nothing and full rollback is explicit and deterministic.

**Recurring disguises / variants**
- `break` where `continue` is required
- Only some state variables update on an error path
- Errors are logged and ignored without restoring invariants
- Winning candidate selected based on partial iteration

**Audit questions**
- Does a single invalid item stop, skip, or bias the rest of the batch?
- Are paired state updates preserved across success and error branches?
- What happens if the first, middle, or last batch element fails?

**Attack surfaces to investigate**

- **Early-exit loop control:** Batch loops over validators, votes, or queued items where a single malformed element triggers `break` instead of `continue`, suppressing processing of all subsequent valid items.
- **Partial state update in comparisons:** Loops that update a "winning" candidate (block, proposal, leader) without also updating the comparison baseline, so iteration order determines the outcome and an attacker who controls ordering controls selection.
- **Unbounded deferred batch size:** Paths where an attacker cheaply queues many small items (micro-stakes, micro-delegations, dust transactions) that are all processed in a single block-finalization batch with no per-block cap, causing liveness failure.

---

## P3. EVM Compatibility Layer Impedance Mismatch

**Broken invariant**
The compatibility layer must preserve the semantic guarantees of the execution environment it claims to emulate.

**Attacker input surface**
Precompiles, bridge adapters, balance handlers, type conversion boundaries, StateDB wrappers, and lifecycle edge cases.

**Trigger condition**
Values or behaviors legal in the native chain but impossible in the reference VM are admitted without a compensating guard.

**State-transition path**
Cross-layer call or EVM action → translation boundary → mismatched semantics → unauthorized effect, inconsistent state, or crash.

**Impact envelope**
Depending on the mismatch, the outcome is fund theft, invariant breakage, or a consensus/liveness failure.

**False-positive signal:** the boundary rejects impossible states early and mirrors reference-client edge behavior exactly.

**Recurring disguises / variants**
- u256 to narrower native balance truncation
- Delegatecall into precompiles that rely on caller identity
- Optimizations that skip writes when state appears unchanged
- StateDB implementations that lose state transitions

**Audit questions**
- Where do native types, permissions, or lifecycle rules differ from the emulated VM?
- Can a call context such as `delegatecall` or internal bridge messaging change authorization meaning?
- Are impossible reference-VM states representable in the host implementation?

**Attack surfaces to investigate**

- **Precompile log forgery via delegatecall:** Precompiles whose logs are trusted as deposit or bridge evidence — if reachable via `delegatecall`, the caller context is preserved, letting an attacker synthesize bridge-valid logs without the corresponding economic action.
- **Impossible-state bridging:** Internal call paths that admit value shapes (negative amounts, overflowed balances) forbidden by the reference VM but representable in the host, causing the host balance routine to misinterpret the value.
- **Dual-accounting drift:** Lifecycle operations (`SELFDESTRUCT`, contract migration, storage clearing) that update one balance view (host or EVM) but not the other, enabling value duplication when the two views diverge.
- **Type-width truncation at conversion boundaries:** Conversions from u256 to narrower native types where the attacker chooses values just above the native boundary, causing the system to accept a full-width amount but settle only the truncated low bits.

---

## P4. Validator Set / Staking Hook State Inconsistency

**Broken invariant**
Validator-set invariants must hold across the full transition, not just before and after it.

**Attacker input surface**
Staking hooks, validator join/leave flows, penalty recovery logic, and any callback that observes or mutates validator membership in-flight.

**Trigger condition**
A hook or callback executes against an intermediate state where coupled validator-set fields have not been updated atomically.

**State-transition path**
Validator transition begins → hook or callback observes partial state → invariant check or downstream action consumes inconsistent membership.

**Impact envelope**
The chain can halt, choose the wrong validator set, or accept duplicate participation.

**False-positive signal:** transitions are atomic or hook visibility is restricted to committed state.

**Recurring disguises / variants**
- Max validator count temporarily exceeded
- Exiting validators still participating in vote processing
- Duplicate validator activity caused by operational failover

**Audit questions**
- Which hooks run while the validator set is only partially updated?
- Can another validator be added, removed, or have penalties reversed during the same transition?
- Do invariant checks run on intermediate or committed membership state?

**Attack surfaces to investigate**

- **Mid-transition hook execution:** Validator join/leave flows where hooks or callbacks observe intermediate state (e.g., active-set count temporarily exceeds maximum) before the atomic update completes, enabling invariant violations.
- **Faulty proposal divergence:** A validator issuing a malformed or conflicting proposal that causes a subset of block producers to fork, splitting the network between nodes that accepted and rejected the proposal.
- **High-availability failover duplication:** Validator operator infrastructure (hot-spare, active-active) where a malfunctioning failover node produces duplicate blocks or votes at the same slot height, creating equivocation conditions.

## references/patterns/client-attack-patterns-2.md

# Client Attack Patterns 5-8

Pattern families extracted from historical blockchain client vulnerabilities across 20+ ecosystems. Mechanism descriptions are preserved for pattern matching.

---

## P5. Vote/Signature Deduplication Failures

**Broken invariant**
Quorum signals must count unique, authorized participants exactly once.

**Attacker input surface**
Vote extensions, observer votes, DAO tallies, validator signatures, and replayable event attestations.

**Trigger condition**
The code increments weight or advances state without proving uniqueness, quorum membership, and message binding.

**State-transition path**
Vote or attestation accepted → uniqueness/quorum check absent or incomplete → state transition executes as if quorum was met.

**Impact envelope**
Effects include halts, forged approvals, incorrect nonces, and double-spend style safety failures.

**False-positive signal:** every accepted vote is keyed by signer, domain, height, and nonce before state changes.

**Recurring disguises / variants**
- Duplicate vote counted twice
- Observer can advance nonce without quorum
- DAO vote stake can be doubled by identity/accounting mismatch
- Voting index inconsistencies allowing the same approval to occupy multiple future slots

**Audit questions**
- What exact key prevents the same voter or observation from being counted twice?
- Is quorum checked before or after state mutation?
- Can replay across height, chain, or message type reuse the same authorization?

**Attack surfaces to investigate**

- **Duplicate vote aggregation:** Vote or attestation pipelines where the deduplication key is incomplete (missing height, domain, or round), allowing the same logical vote to influence aggregation weight more than once.
- **Observer nonce advancement without quorum:** Observer or relayer logic that advances nonce state or marks events as "confirmed" upon receiving a single message, without verifying that a true quorum of distinct signers was reached.
- **Identity/accounting mismatch in governance:** DAO or governance voting where stake weight is derived from a different source than identity deduplication, allowing the same economic weight to be counted through multiple identities.
- **Voting index slot reuse:** Voting data structures where index assignments allow the same logical approval to occupy multiple future slots, enabling double-spend style state evolution across epochs or rounds.

---

## P6. Non-Deterministic Execution Causing Chain Split

**Broken invariant**
Every honest node must derive the same result from the same block inputs and prior state.

**Attacker input surface**
Map iteration, platform-dependent type widths, parser differences, frame decoders, and external dependency sizing rules.

**Trigger condition**
Consensus code depends on iteration order, host architecture, or implementation-specific parsing details.

**State-transition path**
Shared input → implementation- or platform-dependent evaluation → node-specific result → split state or rejected blocks.

**Impact envelope**
Nodes diverge on canonical state, reject each other's blocks, or deadlock migration and replay tooling.

**False-positive signal:** ordering, sizing, and parsing are explicitly canonicalized before use in consensus logic.

**Recurring disguises / variants**
- Map iteration in leader or vote selection
- 32-bit versus 64-bit `usize` or `size_t` behavior
- Decoder disagreement between implementations
- L1 finality assumptions silently embedded in L2 reorg handling

**Audit questions**
- Does consensus logic depend on map order, host word size, or unspecified parser behavior?
- Can two implementations accept the same bytes but decode different frames or limits?
- Are all ordering decisions explicitly sorted and all widths explicitly bounded?

**Attack surfaces to investigate**

- **Unordered map iteration in consensus decisions:** Leader election, tie-breaking, or winner selection logic that iterates over hash maps or sets whose order varies by runtime, causing different nodes to make different but locally valid choices.
- **Architecture-dependent type width in opcodes:** VM instruction implementations or consensus arithmetic that uses platform-dependent types (`int`, `size_t`, `usize`), producing different results on 32-bit vs 64-bit validators.
- **Frame/message decoder disagreement:** Multiple node implementations or versions that decode the same wire bytes into different frames or apply different validity limits, enabling a malicious actor to craft messages that split the network.
- **Implicit L1 finality assumptions in L2 state sync:** Cross-layer state synchronization that silently assumes L1 finality properties (e.g., "blocks older than N are final") without handling upstream reorgs that violate those assumptions.

---

## P7. RPC/API Endpoint Crash via Crafted Input

**Broken invariant**
Public API input must never reach an `unreachable`, nil dereference, or unbounded allocator.

**Attacker input surface**
JSON-RPC, GraphQL, REST, debug endpoints, and import or parser paths exposed to unauthenticated or lightly authenticated callers.

**Trigger condition**
A crafted request exercises an unchecked optional field, impossible-state assertion, or memory-heavy execution path.

**State-transition path**
Remote request → decoder / planner → assertion, nil dereference, or OOM path → node process crash or stall.

**Impact envelope**
The usual result is node-local DoS; if the endpoint is part of migration or consensus tooling, the blast radius can grow to chain halt.

**False-positive signal:** the endpoint enforces bounded resources and treats every parse branch as attacker-controlled.

**Recurring disguises / variants**
- Optional field dereferenced as mandatory
- `unreachable!()` in pagination or graph queries
- Import validation path allowing malformed metadata to reach a panic
- Gas accounting driving an allocator into OOM territory via unusual feature combinations

**Audit questions**
- Which handlers still contain `panic`, `assert`, `unwrap`, or nil dereferences?
- Can an API caller force unusually expensive simulation or parsing behavior?
- Do optional parameters change code paths without complete validation?

**Attack surfaces to investigate**

- **Import/module validation gaps:** RPC or admin endpoints that accept deployment artifacts (WASM modules, bytecode, plugin packages) with insufficient validation, allowing references to non-existent modules or malformed metadata to reach a panic in the execution layer.
- **Feature-combination OOM in simulation:** Simulation or dry-run endpoints where combining multiple features (gas model variants, EIP toggles, precompile sets) creates execution contexts that production blocks would never produce, driving the allocator into OOM territory.
- **"Impossible" branch in query handlers:** Query, pagination, or graph-traversal API paths containing `unreachable!()`, `assert`, or nil dereferences guarded by assumptions about valid state — attackers who can craft the "impossible" parameter combination via the public API can trigger these directly.

---

## P8. Fee / Gas Calculation Errors

**Broken invariant**
Charged fees, refunded fees, and priority ordering must match the actual resource consumption and payer identity.

**Attacker input surface**
Post-handlers, fee sponsorship mechanisms, refund code, base-fee updates, tip accounting, and denomination conversion layers.

**Trigger condition**
The fee pipeline snapshots gas too early, pays the wrong actor, or converts pricing through the wrong denomination or multiplier.

**State-transition path**
Transaction executes → fee snapshot / refund / base-fee update uses wrong context → charges diverge from actual work or payer.

**Impact envelope**
Attackers can underpay, over-refund, inflate priority, or make the fee market misprice subsequent blocks.

**False-positive signal:** the fee engine recomputes against final gas usage and binds all payments to the true spender.

**Recurring disguises / variants**
- Refund sent to fee originator instead of fee sponsor
- Priority boosted by refundable tip
- Base-fee update fed an early gas snapshot
- Same early snapshot mistake infecting block-level policy rather than just refunds

**Audit questions**
- When is gas snapshotted relative to all post-execution work?
- Which account is debited and which account is refunded in fee-sponsorship flows?
- Are denomination conversion and multiplier lookups bound to the actual fee token?

**Attack surfaces to investigate**

- **Fee originator vs fee sponsor confusion:** Fee-sponsorship or fee-grant flows where the refund, receipt, or accounting is directed to the transaction originator instead of the entity that actually funded gas, creating a mis-accounting surface in every sponsored transaction.
- **Gas-limit inflation for fee market manipulation:** Transactions submitted with a gas limit near the block maximum that consume only a small fraction, then manipulate the fee market because the refund or base-fee calculation uses the declared limit rather than actual consumption.
- **Early gas snapshot before post-processing:** Fee pipelines that snapshot gas usage before all post-execution hooks (token transfers, event emission, state cleanup) complete, leaving trailing attacker-influenced operations unaccounted in the fee calculation.
- **Block-level policy poisoning via stale utilization:** Base-fee or congestion pricing algorithms that use the same stale gas snapshot, understating block utilization and mispricing fees for all subsequent users even if no single refund looks anomalous.

## references/patterns/client-attack-patterns-3.md

# Client Attack Patterns 9-12

Pattern families extracted from historical blockchain client vulnerabilities across 20+ ecosystems. Mechanism descriptions are preserved for pattern matching.

---

## P9. P2P / Network Layer Resource Exhaustion

**Broken invariant**
Network ingress must stay cheaper for defenders to reject than for attackers to send.

**Attacker input surface**
P2P gossip, mempool admission, batcher/sequencer buffers, bundle submission, and validator cache management.

**Trigger condition**
An attacker can supply oversized, frequent, or structurally pathological traffic that consumes more memory, CPU, or queue capacity than the protocol charges or limits.

**State-transition path**
Traffic ingress → decode / buffer / rebroadcast / cache → backlog, OOM, or permanent starvation of honest work.

**Impact envelope**
Nodes crash, sequencers stall, validators fall behind, or block production pauses under pressure.

**False-positive signal:** every queue has a hard bound and overload sheds attacker work before honest work.

**Recurring disguises / variants**
- Snappy or frame bombs that fit pre-checks but expand massively
- Large bundles or blocks repeatedly reforwarded
- Hot path caches that grow with fork or backlog pressure
- Unsolicited reply messages pushing data into unbounded caches
- Flat-rate charging for variable-cost operations
- Sustained attacker-controlled backlog growth with insufficient buffer discipline

**Audit questions**
- What is the hardest bound on queue length, decoded size, and retained state per peer?
- Does overload shed attacker work first or honest work first?
- Can one poisoned item block subsequent traffic from being processed?
- Is there a correlation mechanism between outbound requests and accepted replies?
- What is the cost accounting for this message type vs. its actual resource consumption?

**Attack surfaces to investigate**

- **Sustained backlog growth outpacing recovery:** Message or transaction queues where the attacker's injection rate exceeds the node's drain rate, causing the backlog to grow monotonically — each malicious burst leaves the node further behind, with no convergence.
- **State sync size/version mismatch:** State synchronization paths where a message size error or optional protocol upgrade creates a version conflict between peers, halting sync or crashing nodes that receive unexpected payload sizes.
- **Fork-pressure cache unbounding:** Caches (JIT compilation, block candidates, execution results) that grow with fork depth or reorg frequency — an attacker who triggers frequent short forks can accumulate unbounded cache entries until OOM.
- **Per-peer state accumulation without eviction:** Any per-peer or per-connection data structure (pending requests, partial downloads, reassembly buffers) that grows with attacker traffic and lacks hard bounds or eviction, enabling memory exhaustion through sustained connections.

---

## P10. Cross-Layer / Bridge Message Integrity Failures

**Broken invariant**
Cross-domain messages must reflect what actually executed, on the correct domain, exactly once.

**Attacker input surface**
Bridge events, message passers, witness migration tooling, relayer envelopes, and state sync between L1 and L2.

**Trigger condition**
The system treats a message envelope, log, or witness as authoritative without binding it to successful execution, correct domain, or exact parser expectations.

**State-transition path**
Cross-domain action → message/log/witness emitted or parsed incorrectly → relay or migration accepts wrong artifact → remote side acts on false history.

**Impact envelope**
The result is blocked queues, halted migrations, false withdrawals, or incorrect cross-chain state.

**False-positive signal:** messages are committed only after success, include full domain binding, and are parsed by a single canonical implementation.

**Recurring disguises / variants**
- Reverted transactions still emitting bridge-relevant logs
- Migration witness formats disagreeing across producers and consumers
- L1 reorg state sync accepting stale assumptions
- Queue poisoning blocking all legitimate items behind a fabricated event

**Audit questions**
- What proves that a cross-layer message came from successful execution on the intended domain?
- Can two parsers or versions decode the same witness differently?
- What prevents the same event or queue slot from blocking all subsequent progress?

**Attack surfaces to investigate**

- **Reverted-transaction log emission:** Bridge or cross-domain paths that emit events or messages even when the underlying transaction reverts, allowing a relayer to treat failed local execution as authoritative remote intent.
- **Error-type conflation in bridge control flow:** Bridge message handlers that treat distinct error types as equivalent (e.g., "not found" vs "forbidden"), changing control flow and allowing an attacker to redirect or bypass cross-domain processing without a cryptographic break.
- **Migration witness format disagreement:** One-shot migration or upgrade tooling where the witness producer and consumer use different format versions or schema expectations — a single malformed artifact blocks the entire migration pipeline.
- **Queue poisoning via fabricated pending events:** Cross-layer message queues where a fabricated or malformed event can enter a "pending" state that blocks all subsequent legitimate items, causing indefinite liveness failure without stealing funds.

---

## P11. Unbounded Computation in Block Finalization / Block Processing

**Broken invariant**
Per-block work must stay bounded by explicit protocol limits, not attacker-controlled queue length or output size.

**Attacker input surface**
Block-finalization queues, deferred stake removals, WASM output aggregation, large redeem loops, and replay-prone durable nonce logic.

**Trigger condition**
The attacker can enqueue arbitrary work or force replay of expensive processing that is paid once but consumed many times.

**State-transition path**
User actions enqueue or amplify work → block-critical loop drains unbounded set → block exceeds resource budget or replays work incorrectly.

**Impact envelope**
The chain stalls, validators fall over, or critical queues remain permanently behind.

**False-positive signal:** chunking, pagination, per-block quotas, and priced output caps are enforced.

**Recurring disguises / variants**
- No minimum stake amount before queueing removal
- Unlimited stdout/stderr or result payloads from sandboxed execution
- State transition reprocessed because replay markers are incomplete
- Pay-once-execute-many through deferred queue amplification

**Audit questions**
- What caps the number of items or bytes processed in one block?
- Can an attacker pay once to enqueue many future execution costs?
- Does the block processor make progress if one item is pathological?

**Attack surfaces to investigate**

- **No minimum size before deferred queue entry:** Operations (stake removals, undelegations, redemptions) with no minimum amount, allowing an attacker to queue many dust-sized items cheaply and externalize the aggregated processing cost to block finalization.
- **Unbounded output from sandboxed execution:** Sandboxed programs (WASM, smart contracts, user-supplied scripts) whose stdout, stderr, return data, or event logs have no size cap — a malicious program generating heavy output causes OOM in the host.
- **Queue amplification via cheap accumulation:** Any path where the attacker pays a small per-item cost to enqueue work that is processed in bulk later — the exploitability threshold is whether the attacker can accumulate enough items before the expensive batch phase triggers.
- **Incomplete replay markers causing re-execution:** Durable nonce or transaction-replay logic where the "already processed" marker is set too late or not at all on error paths, allowing a failed transaction to be processed again on retry or replay.

---

## P12. ZK Circuit Constraint Insufficiency

**Broken invariant**
Every semantic rule of the virtual machine must be constrained, not merely implied by a witness-construction convention.

**Attacker input surface**
Arithmetic gadgets, queue sorters, memory reads, code unpackers, and proof-system edge cases.

**Trigger condition**
The prover can choose witness values that satisfy the implemented constraints while violating the intended VM semantics.

**State-transition path**
Bad witness chosen → incomplete constraint set still verifies → invalid state transition accepted as proven.

**Impact envelope**
The blast radius is silent state corruption or invalid L2 execution that can be finalized as valid.

**False-positive signal:** every exceptional path, range bound, and queue invariant is explicitly constrained.

**Recurring disguises / variants**
- Remainder not constrained below divisor
- Skipped branch not constrained in the zero or out-of-bounds case
- Queue ordering or version binding only partially enforced
- Zero-divisor cases where the exceptional path is not isolated correctly

**Audit questions**
- What witness freedom remains if the happy-path arithmetic relation is satisfied?
- Are zero, overflow, and out-of-bounds cases constrained independently?
- Can reverted, skipped, or filtered items still leak into committed outputs?

**Attack surfaces to investigate**

- **Unconstrained arithmetic gadgets:** Individual arithmetic operations (multiplication, division, modular reduction) in the circuit where the constraint system does not fully determine the output — a malicious prover who controls the witness can choose values that satisfy the constraints but violate the intended VM semantics.
- **Under-constrained remainder in division:** Division gadgets where the remainder is not constrained to be less than the divisor, leaving the prover with extra witness freedom after satisfying the main relation — the circuit "looks right" but does not uniquely determine the result.
- **Ordering constraints on log/event queues:** Queue or log sorting circuits where reverted, filtered, or out-of-order items can still be arranged into an apparently valid sequence — if ordering is not explicitly constrained, false history becomes provable.
- **Zero-divisor and exceptional-path isolation:** Circuits handling division-by-zero, out-of-bounds access, or overflow cases where the exceptional path is not correctly isolated — the prover can force the circuit into a semantically wrong state transition by choosing witness values that hit the unconstrained exceptional case.

## references/patterns/client-attack-patterns-4.md

# Client Attack Patterns 13-16

Pattern families extracted from historical blockchain client vulnerabilities across 20+ ecosystems. Mechanism descriptions are preserved for pattern matching.

---

## P13. Resource Charging Order Violation (Pay-Before-Execute)

**Broken invariant**
Expensive work must not execute before the system proves that the caller has paid for it and host resources are reclaimed.

**Attacker input surface**
VM instructions, contract loading, host-VM FFI bridges, and native-language ABI ownership boundaries.

**Trigger condition**
The system performs memory clears, contract loads, or native allocations before gas charging or without matching frees.

**State-transition path**
Instruction or host call begins → expensive work / allocation occurs → billing or cleanup is skipped, late, or partial → attacker repeats cheaply.

**Impact envelope**
CPU, memory, or native resources are consumed asymmetrically, enabling DoS or long-lived leaks.

**False-positive signal:** charging and ownership transfer happen before the expensive operation begins.

**Recurring disguises / variants**
- Load contract before charging copy cost
- Allocate native strings or buffers without freeing them across FFI boundaries
- Clear memory or compute witness data before gas validation
- Repeated low-cost calls accumulating unreclaimed resources

**Audit questions**
- Which expensive operations begin before gas or fee charging succeeds?
- Do host-language ownership rules match the FFI allocation strategy?
- Can repeated low-cost calls accumulate unreclaimed resources?

**Attack surfaces to investigate**

- **Unprivileged FFI memory leak accumulation:** Host-VM bridge paths (WASM, native plugins, FFI calls) where each invocation allocates native memory that is never freed by the host-language runtime — repeated unprivileged calls accumulate unreclaimed allocations into network-level memory pressure.
- **Heavy work before gas charge:** VM instructions or host functions that perform expensive operations (memory clearing, data copying, hash computation) before checking whether the caller has sufficient gas — an attacker buys minimal gas and extracts disproportionate validator work.
- **Contract/module load before billing:** Code loading or compilation paths where the expensive contract load, decompression, or JIT compilation executes before the gas or fee check — repeated low-cost calls to non-existent or minimal contracts become a resource extraction tool.

---

## P14. Transaction Replay / Frontrunning / Censorship

**Broken invariant**
A transaction or event must be bound to the right sender, chain, nonce, and context before it influences scarce resources or state.

**Attacker input surface**
Mempools, bridge ingress, observer queues, UTXO tracking, and cross-chain transaction admission logic.

**Trigger condition**
Identity, uniqueness, or chain binding is checked too late or not at all, so a copied payload consumes shared resources or mutates state.

**State-transition path**
Legitimate payload observed → adversary replays or front-runs → scarce slot or state transition consumed before true sender is recognized.

**Impact envelope**
The victim loses inclusion, resources are exhausted, or cross-chain queues remain blocked or inconsistent.

**False-positive signal:** the message is bound to chain ID, sender, nonce, and resource accounting before queuing.

**Recurring disguises / variants**
- Signature valid but sender field unchecked
- Rate limit applied before chain ID validation (enabling cross-chain replay to exhaust limits)
- Queue key does not include enough replay-resistant context
- UTXO reuse in stateless SDK transaction builders
- Queue poisoning via fabricated events that block all legitimate items

**Audit questions**
- What exact tuple makes a payload unique in this system?
- Are replay checks applied before scarce resources such as rate limits or queue slots are consumed?
- Can an attacker partially mutate a copied payload without invalidating the authorization?

**Attack surfaces to investigate**

- **Signature-valid but sender-unverified replay:** Transaction admission paths where payload signature verification passes but the sender/origin field is not independently verified — an attacker who observes a legitimate transaction can replay the same payload from a different sender to front-run or duplicate the action.
- **Stateless UTXO/input selection in client SDKs:** Client SDK transaction-building methods that select inputs (UTXOs, coins, nonces) without tracking in-flight transactions, causing the same input to be selected for multiple transactions within the same block.
- **Rate-limit exhaustion via cross-chain replay:** Rate limiting applied before chain ID or domain validation — attackers replay transactions from other chains to exhaust rate limits for legitimate users on the target chain.
- **Pending-state queue poisoning:** Message or transaction queues where a fabricated or malformed entry enters a "pending" state that blocks all subsequent legitimate items, causing indefinite processing stall without requiring value theft.

---

## P15. Precision Loss in Financial Calculations

**Broken invariant**
Accounting precision must be sufficient to preserve conservation of value across rounding boundaries.

**Attacker input surface**
Reward distribution, weighted loss calculations, share accounting, and conversions between decimal and integer units.

**Trigger condition**
Intermediate precision is truncated or overflowed before the final conservation check, leaving residual value or invalid totals.

**State-transition path**
Value aggregation → intermediate truncation or overflow → final accounting mismatches actual reserves or intended reward split.

**Impact envelope**
Outcomes include locked funds, under-collateralized module accounts, or failed processing when arithmetic exceeds bounds.

**False-positive signal:** the system keeps high-precision intermediates and proves where residual dust is sent.

**Recurring disguises / variants**
- Trimmed decimal reward before checking available funds
- Large weighted value multiplication overflowing bounded integer types
- Integer truncation in share-to-asset conversions allowing rounding exploitation
- Accumulated rounding errors growing as O(N * epsilon) with repeated operations

**Audit questions**
- Where do decimal values become integers, and who absorbs the residual?
- Can attacker-chosen inputs maximize overflow or truncation before invariants run?
- Is value conservation proven on the exact representation used for settlement?

**Attack surfaces to investigate**

- **Iterative multiplication overflow in aggregation:** Aggregation functions (loss calculation, reward distribution, weight computation) that iteratively multiply attacker-influenced values across a collection — malicious data can push intermediate products past the maximum value of the bounded integer type, crashing the computation or wrapping to incorrect results.
- **Precision loss exceeding pool balance:** Reward distribution or fee refund paths where precision loss during truncation/rounding causes the computed payout to exceed the actual pool or module account balance, breaking accounting invariants and potentially locking funds.

---

## P16. Module/Component Wiring Failures

**Broken invariant**
Declared features must be fully registered, initialized, and connected to the components that are supposed to use them.

**Attacker input surface**
Module/component registries, resolver initialization, CLI wiring, spec-to-implementation glue, and infrastructure configuration layers.

**Trigger condition**
A feature compiles or appears configured, but one registration, initialization, or routing step is missing or points to the wrong component.

**State-transition path**
Feature invoked → missing registration / initialization / binding → wrong component, no-op behavior, or spec drift.

**Impact envelope**
The result is often operator-facing failure, but if the missing wiring sits on consensus or fee paths it can escalate into liveness or economic issues.

**False-positive signal:** startup asserts full wiring and integration tests exercise the real runtime path.

**Recurring disguises / variants**
- Component not added to the module/component registry
- Resolver declared but never initialized
- Implementation silently diverges from published spec or reference behavior
- Token factory hooks accepting invalid address assumptions from configuration
- Version hash enforcement missing in integration-layer safety checks

**Audit questions**
- What runtime assertion proves this component is actually wired into the live system?
- Do startup tests exercise the real registration path rather than mocks?
- Is the implemented behavior still aligned with the published spec and operational assumptions?

**Attack surfaces to investigate**

- **Spec-implementation divergence:** Features where the published specification and the actual implementation disagree — integrators and auditors reason about the spec, so a mismatch causes one side to encode or verify the wrong rule, with the divergence potentially exploitable.
- **Configuration-controlled hook with invalid assumptions:** Factory, plugin, or hook registration paths that accept attacker-controlled or operator-controlled configuration (addresses, parameters, feature flags) without validating assumptions — ordinary user flows can then hit the misconfigured hook.
- **Source-present but unwired module:** Modules or components that exist in source code and compile successfully but are never fully registered or initialized in the live application — the vulnerability is in integration/wiring code that operators rarely inspect.
- **Missing version hash binding in code loading:** Code unpacking or loading paths that do not bind the loaded bytecode to the version hash promised by the deployment artifact — downstream layers reason about the wrong bytecode semantics, enabling logic bypass.

## references/patterns/client-attack-patterns-5.md

# Client Attack Patterns 17-20

Pattern families covering memory safety, concurrency, undefined behavior, and serialization — the top CVE classes for C/C++ and Rust clients. Mechanism descriptions are preserved for pattern matching.

---

## P17. Memory Safety Violations

**Broken invariant**
Every memory access must target validly allocated, correctly sized, and still-owned memory. No read or write may occur outside allocation bounds, after deallocation, or through an invalidated reference.

**Attacker input surface**
P2P message handlers, RPC request parsers, transaction deserialization, consensus state accessors, FFI bridge boundaries, and any code path that operates on raw pointers, iterators, or `unsafe` blocks.

**Trigger condition**
Attacker-controlled input influences a pointer, index, or allocation size in code that lacks bounds checking, lifetime enforcement, or ownership tracking.

**State-transition path**
Malformed input → unchecked index, dangling pointer, or integer overflow in size calculation → out-of-bounds read/write, use-after-free, or double-free → heap corruption, information leak, or arbitrary code execution.

**Impact envelope**
Remote code execution is the ceiling. Heap corruption can be weaponized for arbitrary write primitives. Information leaks expose keys or internal state. Even non-exploitable crashes constitute DoS.

**False-positive signal:** all pointer accesses are bounds-checked, all lifetimes are enforced by RAII/smart pointers, and all allocations are matched with exactly one deallocation.

**Applicable to:** C, C++, unsafe Rust. Skip for Go, Java, safe Rust, and other memory-managed languages.

**Recurring disguises / variants**
- Use-after-free: object freed by one thread/callback while another still holds a reference
- Buffer overflow: attacker-controlled length field used directly as memcpy size or array index
- Double-free: error path frees a buffer, then the normal cleanup path frees it again
- Uninitialized read: stack or heap buffer used before being fully written, leaking previous contents
- Iterator invalidation: container modified (insert/erase) while iteration is in progress
- Integer overflow in allocation: `count * element_size` wraps to a small value, allocating too little

**Audit questions**
- Who owns the memory being accessed? Can the owner deallocate it while this code path runs?
- Are all array/buffer accesses preceded by a bounds check against the actual allocation size?
- Do any integer calculations (addition, multiplication) determine allocation sizes or offsets? Can they wrap?
- For each `unsafe` block in Rust: what invariants must hold for the surrounding safe code to remain sound?
- For C++ containers: can any concurrent or callback-driven code path insert/erase while iteration is active?
- At every FFI boundary: which side allocates, which side frees, and is the contract enforced?

**Attack surfaces to investigate**

- **Async handler holding raw pointer across peer lifetime:** Message handlers that store a raw pointer or reference to a peer's buffer and process the data asynchronously — if the peer disconnects before processing completes, the buffer is freed and the handler writes through a dangling pointer, enabling heap corruption or RCE.
- **Wire length field passed directly to allocator:** Deserialization paths where a length field from the wire (32-bit or 64-bit) is used directly as an allocation size or vector resize argument without validation — attacker-chosen values can cause integer overflow (wrapping to a small allocation) followed by out-of-bounds writes.
- **Iterator invalidation via concurrent container modification:** Handlers that iterate over shared containers (maps, vectors, sets) while concurrent threads or callbacks insert or erase elements — the iterator is invalidated mid-loop, dereferencing freed or relocated memory.
- **Use-after-free across timeout/event boundaries:** State machines that free objects (validator records, peer sessions, transaction contexts) on timeout or disconnection while other code paths still hold references — the next event using the stale reference triggers use-after-free and potential state corruption.

---

## P18. Concurrency Defects

**Broken invariant**
Shared mutable state must be accessed atomically with respect to all concurrent observers and modifiers. Lock acquisition must follow a consistent total order to prevent deadlock.

**Attacker input surface**
Any handler called from multiple threads or async tasks that reads or writes shared state: peer connection maps, mempool data structures, consensus round state, caches, and metrics counters.

**Trigger condition**
Two or more threads access the same data without sufficient synchronization, or locks are acquired in inconsistent orders across different code paths.

**State-transition path**
Concurrent access → data race (torn read/write), TOCTOU gap (check-then-act without holding lock), or lock ordering violation → corrupted state, lost updates, deadlock, or logic bypass.

**Impact envelope**
Data races can corrupt consensus state (chain split), lose transactions (fund loss), or crash the node (DoS). Deadlocks halt the node. TOCTOU bugs can bypass authorization or double-spend.

**False-positive signal:** all shared state is protected by a single lock held for the entire read-modify-write, or if the code uses lock-free structures with correct memory ordering.

**Applicable to:** Multi-threaded clients in any language. Skip for single-threaded runtimes.

**Recurring disguises / variants**
- Data race: two threads read-modify-write a counter or map entry without mutual exclusion
- TOCTOU: handler checks a condition (e.g., "peer is authorized"), releases lock, then acts on stale result
- Deadlock: thread A holds lock X and waits for lock Y; thread B holds lock Y and waits for lock X
- Atomicity violation: a multi-step state update is interrupted between steps, leaving inconsistent state
- Signal handler races: async signal handler accesses data structures that the main thread is modifying
- Missed notification: condition variable signaled before the waiter enters wait, causing indefinite block

**Audit questions**
- For each shared data structure: what lock protects it, and is the lock held for the entire read-modify-write?
- Is there a TOCTOU gap between checking a condition and acting on it?
- What is the global lock acquisition order? Can any two code paths acquire locks in different orders?
- Are there any lock-free data structures? Are memory ordering constraints (acquire/release/seq_cst) correct?
- Can an attacker control timing (e.g., by sending messages at specific intervals) to widen race windows?
- For async/await code: can a yield point occur between a check and its dependent action?

**Attack surfaces to investigate**

- **Check-then-act TOCTOU on connection limits:** Peer management code that checks a count or condition under a read lock, releases it, then acts under a write lock — under heavy connection churn, the gap allows the count to exceed maximums, exhausting file descriptors or memory.
- **Split-lock state inconsistency:** Data structures where different aspects (e.g., mempool contents vs fee accounting, validator set vs round state) are protected by different locks — carefully timed operations can cause the two views to diverge, enabling priority manipulation or incorrect state transitions.
- **Lock ordering inversion between subsystems:** Two or more code paths that acquire the same set of locks in different orders (e.g., validator-set lock then round-state lock vs the reverse) — adversarial timing can trigger deadlock, halting the node.
- **Unsynchronized pointer read across threads:** Handlers that read shared pointers (best block, chain tip, latest state root) without holding the appropriate lock — concurrent updates can produce torn reads on non-atomic architectures, returning partially constructed objects and crashing on invalid field access.

---

## P19. Undefined / Platform-Dependent Behavior

**Broken invariant**
Consensus-critical code must produce identical, defined results on every supported platform, compiler, and configuration. No operation may invoke language-level undefined behavior.

**Attacker input surface**
Arithmetic operations, type casts, pointer arithmetic, bit manipulation, floating-point calculations, and any code compiled with optimization that relies on UB-free assumptions.

**Trigger condition**
Attacker-controlled input reaches an operation whose behavior is undefined by the language standard (C/C++ UB) or varies across platforms (type widths, endianness, floating-point rounding).

**State-transition path**
Attacker input → undefined or platform-dependent operation → compiler optimizes away safety checks, or different platforms compute different results → node crash, consensus split, or security bypass.

**Impact envelope**
UB can cause compilers to eliminate safety checks (e.g., overflow checks optimized away because "signed overflow can't happen"), leading to exploitable logic changes. Platform-dependent behavior causes consensus divergence.

**False-positive signal:** all arithmetic uses defined-overflow types, all casts are bounds-checked, and all consensus arithmetic avoids floating-point.

**Applicable to:** C, C++ primarily. Also relevant to Rust FFI and assembly blocks. Less relevant to Go (defined overflow semantics) and safe Rust (panics on overflow in debug, wraps in release).

**Recurring disguises / variants**
- Signed integer overflow: C/C++ UB that compilers exploit to remove "impossible" branches
- Strict aliasing violation: accessing memory through incompatible pointer types, enabling miscompilation
- Null pointer dereference in context where compiler assumed non-null (UB-based optimization)
- Platform-dependent `sizeof`: `size_t`, `long`, or `int` width differs between 32-bit and 64-bit
- Floating-point non-determinism: different rounding modes or FMA availability across CPUs
- Unsequenced side effects: order of evaluation varies between compilers for complex expressions
- Bit shift by type width: `1 << 32` on a 32-bit int is UB in C/C++

**Audit questions**
- Are there any signed integer arithmetic operations on attacker-controlled values? Can they overflow?
- Does consensus code use `int`, `long`, `size_t`, or other platform-dependent types?
- Is floating-point arithmetic used in any consensus or fee calculation?
- Are there casts between pointer types that could violate strict aliasing?
- Does the code rely on specific evaluation order for expressions with side effects?
- For each bit shift: is the shift amount guaranteed to be less than the type width?

**Attack surfaces to investigate**

- **Signed overflow eliminating safety checks:** Fee, reward, or balance calculations using signed integer multiplication on attacker-controlled values — when overflow occurs, the compiler (exploiting C/C++ UB) may optimize away the subsequent overflow check, producing negative values or bypassing limits.
- **Platform-dependent type width in consensus arithmetic:** Consensus calculations (vote weight aggregation, stake totals, block size limits) using `int`, `long`, or `size_t` — different results on 32-bit vs 64-bit validators can be triggered by an attacker who pushes values past the 32-bit boundary, splitting the network by architecture.
- **Floating-point non-determinism in state transitions:** Block reward, fee distribution, or penalty calculations using `float`/`double` for intermediate results — different CPUs, compilers, or optimization levels produce subtly different rounding, accumulating state root divergence over many blocks.
- **Strict aliasing violation in serialization:** Serialization or deserialization routines that cast between incompatible pointer types (`char*` to `uint64_t*`) for performance — the strict aliasing violation causes compiler reordering of reads and writes, producing corrupted output on optimized builds but correct output on debug builds.

---

## P20. Serialization Boundary Hardening

**Broken invariant**
Every deserialized message must be structurally valid, bounded in resource consumption, canonically encoded, and round-trip consistent before it influences any node state.

**Attacker input surface**
P2P protocol messages, RPC request bodies, transaction payloads, block headers, state sync snapshots, and any data crossing a trust boundary via wire format (protobuf, RLP, SSZ, borsh, SCALE, JSON, custom binary).

**Trigger condition**
The parser accepts input that is structurally valid at the wire level but violates semantic constraints: excessive nesting depth, length-prefix values exceeding available data, non-canonical encoding of the same logical value, or round-trip asymmetry where `encode(decode(x)) != x`.

**State-transition path**
Malformed wire data → parser accepts without full validation → excessive allocation (nesting bomb), incorrect comparison (non-canonical), or state divergence (round-trip asymmetry) → DoS, consensus split, or logic bypass.

**Impact envelope**
Nesting/size bombs cause OOM (DoS). Non-canonical encodings cause hash mismatches or comparison failures (consensus split). Round-trip asymmetry causes signatures to verify against different data than what was executed (logic bypass, potential fund theft).

**False-positive signal:** the parser enforces maximum depth/size before allocation, rejects non-canonical forms, and the codebase proves round-trip consistency for all serialized types.

**Applicable to:** All blockchain clients regardless of language. Every client has serialization boundaries.

**Recurring disguises / variants**
- Nesting depth bomb: deeply nested protobuf/JSON/RLP structures cause stack overflow or exponential parsing time
- Length-prefix overflow: a 4-byte length field claims more data than the message contains; parser allocates based on claim
- Non-canonical encoding: the same integer encoded as 1 byte or 5 bytes; different nodes hash different encodings
- Round-trip asymmetry: decode accepts relaxed input but encode produces strict output; signature verification uses re-encoded form
- Field ordering ambiguity: serialization format allows reordering of fields; different orderings produce different hashes
- Trailing garbage: parser succeeds but ignores trailing bytes; different implementations consume different amounts

**Audit questions**
- Is there a maximum nesting depth enforced during parsing? What happens if exceeded — error or panic?
- Are length-prefixed fields validated against remaining message bytes BEFORE allocation?
- Can the same logical value be encoded in multiple byte sequences? Does the parser reject non-canonical forms?
- Does `encode(decode(x)) == x` hold for all accepted inputs? Where is this tested?
- Are there any fields where declared size could be negative (signed integer) or exceed 2^31?
- Does the parser consume exactly the expected number of bytes, or can trailing data be silently ignored?

**Attack surfaces to investigate**

- **Unbounded nesting depth in recursive parsing:** Protocol message formats (protobuf, JSON, RLP, custom binary) where nested structures are parsed recursively without a depth limit — an attacker sends a deeply nested message (thousands of levels) to overflow the stack and crash the node.
- **Non-canonical integer encoding causing hash divergence:** Serialization formats that allow the same integer value to be encoded in multiple ways (leading zero bytes, variable-length encoding) — different node implementations may canonicalize differently when computing hashes, causing consensus splits on blocks containing non-canonical fields.
- **Round-trip asymmetry bypassing signature verification:** Wire formats where the decoder accepts relaxed/non-canonical input but the signature verification path re-encodes canonically before hashing — an attacker submits data where the signed bytes differ from the executed bytes, bypassing authorization.
- **Length-prefix allocation before data validation:** Deserialization paths where a length-prefix field (32-bit or 64-bit) determines allocation size, and the parser allocates before verifying that the remaining message actually contains that many bytes — an attacker sends a message with a multi-GB length claim to cause OOM before any application-level validation.

## references/report-format.md

# Report Format

What a strong audit report looks like. The key properties: findings are organized by severity, each finding has enough detail to reproduce and verify, and coverage is honestly documented. Adapt the structure to fit the specific audit.

---

## Report Structure (example)

```markdown
# [Project Name] Security Audit Report

**Audit Date:** [YYYY-MM-DD]
**Target:** [repository, branch/commit]
**Scope:** [subsystems analyzed, lines of code reviewed]

---

## Executive Summary

[2-4 paragraphs covering:]
- What was analyzed and what was not
- Finding counts by severity
- Key conclusions: the 3-5 most important findings or observations
- Adversarial review results (if deep mode was used)

---

## Severity Summary

| Severity | Count | Key Areas |
|----------|-------|-----------|
| Critical | [N] | [affected subsystems] |
| High | [N] | [affected subsystems] |
| Medium | [N] | [affected subsystems] |
| Low | [N] | [affected subsystems] |
| Info | [N] | [affected subsystems] |
| **Total** | **[N]** | |

---

## Findings

### CRITICAL Severity
### HIGH Severity
### MEDIUM Severity
### LOW Severity
### INFORMATIONAL

[Each section: summary table, then detailed findings]

---

## Coverage Summary

[What was analyzed, what was not, and why]

---

## Adversarial Review Summary (if applicable)

[Table of reviewed findings with verdicts]
```

---

## Individual Finding (example)

A well-structured finding contains enough detail for someone else to reproduce, verify, and fix it. Here is what that looks like:

```markdown
### [ID]: [Short Title]

| Field | Value |
|-------|-------|
| **Severity** | [Critical / High / Medium / Low / Info] |
| **Confidence** | [0-100] |
| **Pattern** | [P1-P20 ID and name, or "None — heuristic finding"] |
| **Location** | [file:line_start-line_end] |
| **Entry Point** | [How an attacker reaches this code] |
| **Impact** | [What happens if exploited] |

#### Description

[2-4 sentences. What the code does, what it fails to do, what an attacker achieves.]

#### Trigger Scenario

1. Attacker [action] via [entry point]
2. Message/request reaches [handler] at [file:line]
3. [Missing check / incorrect logic] allows [bad state]
4. Result: [concrete impact with numbers]

#### Quantitative Assessment

[Resource consumption math, if applicable:]
- Cost per unit: [bytes / reads / cycles]
- Units per message: [calculation]
- Rate limit: [messages before cutoff]
- Total impact: [resource × units × messages]
- Time to impact: [total / capacity]

#### Existing Mitigations

- [Mitigation 1]: [effectiveness assessment]
- [Mitigation 2]: [effectiveness assessment]

#### Missing Defenses

- [ ] [Defense 1]: [why it matters]
- [ ] [Defense 2]: [why it matters]

#### Recommendation

[Concrete fix, 1-3 sentences, referencing specific code locations.]

#### Adversarial Review (if applicable)

| Role | Verdict | Key Argument |
|------|---------|-------------|
| Red Team | [assessment] | [core argument] |
| Blue Team | [assessment] | [core argument] |
| **Judge** | **[TRUE / PARTIAL / FALSE]** | [reasoning with code refs] |
```

---

## Finding ID Convention

Format: `[SUBSYSTEM]-[PATTERN_ID]-[SEQUENCE]`

Each agent prefixes finding IDs with its subsystem name (from the manifest) to prevent collisions between parallel agents. The cross-subsystem agent uses `xsub` as its prefix.

- `p2p-P9-01` — First P9 finding from the p2p hunt agent
- `consensus-P6-01` — First P6 finding from the consensus hunt agent
- `transactions-P1-03` — Third P1 finding from the transactions hunt agent
- `rpc-HEURISTIC-01` — First heuristic finding from the rpc hunt agent
- `xsub-P10-01` — First P10 finding from the cross-subsystem agent

When a finding maps to multiple patterns, use the primary pattern for the ID and note secondary patterns in the body.

---

## Coverage Summary Format

The coverage summary describes work done, not a metric to optimize:

```markdown
## Coverage Summary

### Analyzed
- [Subsystem 1]: [entry points examined, what was checked]
- [Subsystem 2]: [entry points examined, what was checked]

### Not Analyzed
- [Subsystem 3]: [why — out of scope, insufficient context, lower risk priority]
- [Subsystem 4]: [why]

### Partially Analyzed
- [Subsystem 5]: [what was checked, what remains]
```

---

## Adversarial Review Summary Table

When deep mode is used and findings are reclassified:

```markdown
| ID | Original Severity | Final Severity | Judge Verdict | Reasoning |
|----|-------------------|----------------|---------------|-----------|
| [ID] | HIGH | [new severity] | [TRUE/PARTIAL/FALSE] | [summary] |
```

Findings not selected for adversarial review: note as "not adversarially reviewed" with initial severity retained.

---

## What Makes Findings Actionable

Findings that reference specific code locations and include concrete numbers are more actionable than vague descriptions:

- **Specificity** — "No limit on `message.items_count()` in handler path" is actionable; "unbounded input" is not
- **Code references** — Findings that cite `file:line` can be verified and fixed; findings without them cannot
- **Quantitative math** — Resource findings with concrete calculations (cost × rate × time = impact) are convincing; "could be large" is not
- **Missing defenses** — Listing what should exist but doesn't gives developers a clear fix target
- **Fact vs judgment** — Descriptions that state facts and recommendations that state opinions are clearer than mixing both
- **Pattern IDs** — Using P1-P20 enables cross-referencing across findings and future audits

