Trigger Pattern Always required for Solana audits - Inject Into Breadth agents, depth agents
Scanned 5/27/2026
Install via CLI
openskills install PlamenTSV/plamen---
name: "account-validation"
description: "Trigger Pattern Always required for Solana audits - Inject Into Breadth agents, depth agents"
---
# ACCOUNT_VALIDATION Skill
> **Trigger Pattern**: Always required for Solana audits
> **Inject Into**: Breadth agents, depth agents
> **Finding prefix**: `[AV-N]`
> **Rules referenced**: S1, S6, S7, S8, R4
For every instruction handler in the Solana program:
## 1. Account Type Inventory
For EACH instruction, list every account with expected constraints:
| # | Account Name | Expected Owner | Expected Type (Discriminator) | Mutable? | Signer? | Constraints (has_one, seeds, etc.) |
|---|-------------|----------------|-------------------------------|----------|---------|-----------------------------------|
| 1 | {name} | {program_id / system / token} | {Account<T> / UncheckedAccount / etc.} | YES/NO | YES/NO | {list all} |
**Anchor auto-checks**: Anchor's `Account<T>` validates owner + discriminator automatically. `UncheckedAccount` / `AccountInfo` do NOT - manual validation required.
## 2. Owner Check Audit
For each `AccountInfo` or `UncheckedAccount` usage:
| Account | Owner Validated? | Validation Location | Correct Owner? | Missing? |
|---------|-----------------|---------------------|---------------|----------|
| {name} | YES/NO | {line} | {expected vs actual} | FLAG if NO |
**Critical pattern**: Any `AccountInfo` deserialized without prior owner check → arbitrary data injection.
**Anchor pattern**: `#[account(owner = expected_program)]` or manual `require!(account.owner == &expected_id)`.
## 3. Discriminator Check
For all accounts deserialized from raw data:
| Account | Uses Account<T>? | Discriminator Checked? | Can Substitute Different Account Type? |
|---------|------------------|----------------------|---------------------------------------|
| {name} | YES/NO | YES/NO (Anchor auto) | {if NO: what types could be substituted} |
**Attack**: Pass an account of Type B where Type A is expected - different data layout, fields interpreted incorrectly.
**Safe**: Anchor's `Account<T>` checks the 8-byte discriminator. Manual programs must check explicitly.
**Anchor IDL buffer amplification**: If the program uses Anchor with the default IDL feature enabled (check Cargo.toml for `idl-build` feature or absence of `no-idl` — enabled by default), `IdlCreateBuffer` is a permissionless instruction that lets ANYONE create program-owned accounts with nearly arbitrary data at arbitrary lengths. This means a missing discriminator check is exploitable even when no other account type in the program has a suitable layout for cosplay — the attacker crafts one via `IdlCreateBuffer`. When flagging a discriminator bypass: if IDL feature is enabled, severity is NOT mitigated by "no suitable account type exists for substitution."
## 4. Data Matching (Cross-Account References)
For each cross-account reference (has_one, constraint, seeds):
| Instruction | Account A | Account B | Relationship | Validated? | Bypass? |
|-------------|-----------|-----------|-------------|-----------|---------|
| {ix} | {a} | {b} | {a.field == b.key()} | YES/NO | {if NO: how to exploit} |
**Pattern**: Ensure that when Account A references Account B (e.g., `vault.mint == mint.key()`), the relationship is enforced on-chain.
**Attack**: Substitute a different mint account that the vault doesn't actually belong to.
## 5. Remaining Accounts Audit
For each use of `ctx.remaining_accounts`:
| Instruction | Remaining Account Usage | Owner Validated? | Type Validated? | Signer Checked? | Data Validated? |
|-------------|------------------------|-----------------|----------------|-----------------|-----------------|
| {ix} | {purpose} | YES/NO | YES/NO | YES/NO | YES/NO |
**Critical**: `remaining_accounts` bypass Anchor's automatic validation. Every field must be checked manually.
**Attack**: Inject attacker-controlled accounts via remaining_accounts to redirect funds or corrupt state.
## 6. Duplicate Account Detection
For each instruction with 2+ mutable accounts:
| Instruction | Mutable Account A | Mutable Account B | Key Uniqueness Enforced? | Self-Transfer Risk? |
|-------------|-------------------|-------------------|------------------------|-------------------|
| {ix} | {a} | {b} | YES/NO | {if NO: impact of a==b} |
**Attack (S7)**: Pass the same account as both `from` and `to` in a transfer → potential balance inflation.
**Defense**: `require!(account_a.key() != account_b.key())` or Anchor `constraint`.
## 7. Sysvar Validation
For each sysvar account passed as input:
| Sysvar | Passed As | Address Validated? | Could Be Spoofed? |
|--------|-----------|-------------------|-------------------|
| Clock | AccountInfo | YES/NO | {if NO: attacker controls time} |
| Rent | AccountInfo | YES/NO | {if NO: attacker controls rent} |
| Instructions | AccountInfo | YES/NO | {if NO: Wormhole-style attack} |
**Safe pattern**: Use `Sysvar::from_account_info()` or `_checked` variants.
**Unsafe pattern**: Raw deserialization of sysvar data from unchecked AccountInfo.
## 8. Trust Chain Analysis
For each account validation chain, trace to its root:
| Account | Validated Against | Root Trust Anchor | Chain Complete? |
|---------|------------------|-------------------|----------------|
| {account} | {what validates it} | PDA / Program ID / Hardcoded pubkey / NONE | YES/NO |
**Pattern**: Validation chain must root in a known-good value. If chain roots in user input → FINDING.
**Example**: `authority` validated against `vault.authority`, `vault` validated against PDA seeds → chain roots in PDA (good).
## Finding Template
```markdown
**ID**: [AV-N]
**Severity**: [based on what attacker can do with invalid account]
**Step Execution**: ✓1,2,3,4,5,6,7,8 | ✗(reasons) | ?(uncertain)
**Rules Applied**: [S1:✓, S6:✓/✗, S7:✓/✗, S8:✓/✗, R4:✓/✗]
**Location**: program/src/instructions/{file}.rs:LineN
**Title**: Missing [validation type] for [account] in [instruction] enables [attack]
**Description**: [Specific missing validation with code reference]
**Impact**: [What attacker can achieve: fund theft, state corruption, DoS]
```
---
## Step Execution Checklist (MANDATORY)
| Section | Required | Completed? | Notes |
|---------|----------|------------|-------|
| 1. Account Type Inventory | YES | ✓/✗/? | For every instruction |
| 2. Owner Check Audit | YES | ✓/✗/? | For every AccountInfo/UncheckedAccount |
| 3. Discriminator Check | YES | ✓/✗/? | For all deserialized accounts |
| 4. Data Matching | YES | ✓/✗/? | For all cross-account references |
| 5. Remaining Accounts Audit | IF remaining_accounts used | ✓/✗(N/A)/? | Manual validation check |
| 6. Duplicate Account Detection | YES | ✓/✗/? | For all mutable account pairs |
| 7. Sysvar Validation | IF sysvars passed as AccountInfo | ✓/✗(N/A)/? | Address validation |
| 8. Trust Chain Analysis | YES | ✓/✗/? | Chain to root trust anchor |
No comments yet. Be the first to comment!