{
  "summary": {
    "total_findings": 6,
    "critical_count": 2,
    "high_count": 2,
    "medium_count": 1,
    "low_count": 1,
    "informational_count": 0,
    "likely_false_positive_count": 0
  },
  "findings": [
    {
      "id": "finding-0",
      "title": "Missing Signer Verification in update_authority",
      "description": "The `UpdateAuthority` accounts struct declares `authority` as `SystemAccount` instead of `Signer`. Combined with `has_one = authority`, this allows any user to invoke the instruction by including the current authority's public key as a non-signer account in the transaction. The `has_one` constraint is satisfied without requiring an actual signature from the authority wallet, enabling anyone to change the bank authority to an address they control and subsequently drain funds.",
      "severity": "Critical",
      "confidence": "Medium",
      "category": "AccessControl",
      "location": {
        "file": "src/lib.rs",
        "line_start": 78,
        "line_end": 88
      },
      "references": [
        {
          "url": "https://github.com/slowmist/solana-smart-contract-security-best-practices",
          "description": "SlowMist Solana smart contract security best practices"
        }
      ],
      "verification_notes": "Verifier confirmed the finding: `authority` is passed as a non-signer account and `has_one` only checks key equality, so any wallet can call `updateAuthority`.",
      "is_likely_false_positive": false,
      "remediation": "Change `authority: SystemAccount` to `authority: Signer` in `UpdateAuthority` and keep the `has_one` constraint. The Signer constraint makes Anchor require the current bank authority's signature, so only the true owner can rotate it.",
      "poc": "await program.methods.updateAuthority().accounts({ newAuthority: attacker }).instruction();\nawait program.methods.withdraw(new anchor.BN(amount)).accounts({ authority: attacker }).instruction();"
    },
    {
      "id": "finding-1",
      "title": "First Depositor Can Become Bank Authority",
      "description": "The `deposit` instruction uses `init_if_needed` and, when `is_initialized` is false, sets `bank.authority` to the caller's public key. Any user can become the bank authority simply by being the first to deposit (e.g., with 1 lamport). Once in control, combined with the missing signer check in `update_authority` and the unrestricted `withdraw` instruction, an attacker can drain all funds from the bank.",
      "severity": "Critical",
      "confidence": "Medium",
      "category": "AccessControl",
      "location": {
        "file": "src/lib.rs",
        "line_start": 10,
        "line_end": 32
      },
      "references": [
        {
          "url": "https://github.com/slowmist/solana-smart-contract-security-best-practices",
          "description": "SlowMist Solana smart contract security best practices"
        }
      ],
      "is_likely_false_positive": false,
      "remediation": "Replace `init_if_needed` with `init` plus an explicit initialization check, or use `init_if_needed` only when the account is guaranteed fresh. Alternatively, only honor the `is_initialized` flag when it was set by a genuine initializer (e.g., require the first depositor's signature once, via a dedicated `initialize` instruction)."
    },
    {
      "id": "finding-2",
      "title": "Unchecked Arithmetic Operations on bank_balance",
      "description": "The `bank_balance` field is modified using unchecked `+=` and `-=` operators in `deposit` and `withdraw`. While the Solana runtime reverts on overflow/underflow, using checked arithmetic (`checked_add`, `checked_sub`) is recommended for financial code to provide explicit error handling and clearer error reporting instead of relying on runtime panics.",
      "severity": "High",
      "confidence": "Medium",
      "category": "NumericalIssue",
      "location": {
        "file": "src/lib.rs",
        "line_start": 12,
        "line_end": 35
      },
      "references": [
        {
          "url": "https://github.com/slowmist/solana-smart-contract-security-best-practices",
          "description": "SlowMist Solana smart contract security best practices"
        }
      ],
      "is_likely_false_positive": false,
      "remediation": "Use checked arithmetic: `bank.bank_balance = bank.bank_balance.checked_add(amount) .ok_or(BankError::Overflow)?` in `deposit`, and checked_sub in `withdraw`."
    },
    {
      "id": "finding-3",
      "title": "Missing Balance Validation in withdraw",
      "description": "The `withdraw` instruction does not verify that `bank_balance >= amount` before performing the subtraction and the lamport transfer. This allows users to attempt withdrawals larger than the available balance, causing transaction failures at the arithmetic underflow step, wasting compute and producing a poor user experience. The lamport transfer via `sub_lamports` would also fail if insufficient balance exists.",
      "severity": "High",
      "confidence": "Medium",
      "category": "InputValidation",
      "location": {
        "file": "src/lib.rs",
        "line_start": 34,
        "line_end": 40
      },
      "references": [
        {
          "url": "https://github.com/slowmist/solana-smart-contract-security-best-practices",
          "description": "SlowMist Solana smart contract security best practices"
        }
      ],
      "is_likely_false_positive": false,
      "remediation": "Add `require!(bank.balance >= amount, BankError::InsufficientFunds)` before the subtraction and transfer, and map the error to a user-friendly failure."
    },
    {
      "id": "finding-4",
      "title": "Missing Zero-Amount Validation in deposit and withdraw",
      "description": "Neither `deposit` nor `withdraw` validates that the `amount` parameter is greater than zero. Zero-amount operations are accepted, which wastes compute, pollutes on-chain state and event logs (via `msg!`), and can confuse off-chain indexers and UIs that track deposits and withdrawals.",
      "severity": "Medium",
      "confidence": "Medium",
      "category": "InputValidation",
      "location": {
        "file": "src/lib.rs",
        "line_start": 10,
        "line_end": 40
      },
      "references": [
        {
          "url": "https://github.com/slowmist/solana-smart-contract-security-best-practices",
          "description": "SlowMist Solana smart contract security best practices"
        }
      ],
      "is_likely_false_positive": false,
      "remediation": "Add `require!(amount > 0, BankError::ZeroAmount)` to both `deposit` and `withdraw`."
    },
    {
      "id": "finding-5",
      "title": "State Update Before External Transfer in deposit",
      "description": "In the `deposit` instruction, `bank_balance += amount` is executed before the CPI `transfer` of lamports to the bank PDA. Although Solana transactions are atomic (a CPI failure reverts all state changes), modifying internal state before performing the external interaction violates the checks-effects-interactions pattern and is considered risky practice. If any non-CPI failure path were introduced later, the state could become desynchronized from actual lamport holdings.",
      "severity": "Low",
      "confidence": "Medium",
      "category": "StateManagement",
      "location": {
        "file": "src/lib.rs",
        "line_start": 11,
        "line_end": 30
      },
      "references": [
        {
          "url": "https://github.com/slowmist/solana-smart-contract-security-best-practices",
          "description": "SlowMist Solana smart contract security best practices"
        }
      ],
      "is_likely_false_positive": false,
      "remediation": "Perform the CPI transfer first, then update `bank_balance` (checks-effects-interactions)."
    }
  ],
  "metadata": {
    "analyzer_name": "Odin Scan",
    "analyzer_version": "0.5.2",
    "timestamp": "2026-09-02T16:07:26Z",
    "contract_path": "Odinscan Demo - bank_two (Solana Developer Bootcamp)",
    "commit_hash": "8aa304d1"
  }
}