Expert · LESSON 01 OF 06
1. Threat-model a Solana protocol
By the end, you can map protocol assets, account trust boundaries, attacker capabilities, and observable security evidence.
Read the workflow
Start from the protocol’s protected state and identify every authority able to change it. Trace plausible attack paths through caller-controlled accounts, signatures, program invocations, or operational keys. For each path, name an enforcement control and a negative test; separately identify monitoring, pause, and incident response evidence that runtime tests cannot provide.
- PROTOCOL STATE
- AUTHORITIES
- ATTACK PATHS
- CONTROLS
- TEST + RESPONSE
FIELD NOTE 01
Start with a system and its invariants
Choose one concrete system, such as a token vault, marketplace escrow, staking pool, or credential issuer. State what must always remain true: only the intended authority can move pooled assets, a receipt represents the correct deposit, and a failed instruction cannot leave a partial business result. Describe the normal user journey before listing attacks. A threat model is scoped to a version of a system and its dependencies; “Solana is secure” or “we use Anchor” does not establish that a particular program checks the right accounts.
FIELD NOTE 02
Map state and authorities
On Solana, programs contain executable code while mutable application state lives in separate accounts passed to instructions. Record each important account’s address derivation, owning program, data fields, lamports, and authority. Ask which program may modify its data and which signer may authorize a transition. For a vault, distinguish the token mint, vault token account, authority PDA, user token account, and executable program. A matching display name or token symbol is not enough: the mint address and owning token program must match the protocol’s expectation.
FIELD NOTE 03
Trace the transaction boundary
A transaction message names its instructions, accounts, and required signers. Treat account addresses, instruction bytes, and client-selected options as attacker-controlled until the program validates them. For every instruction, write down which accounts must be writable, which signer authorizes the action, and the relationships that must hold among them. A user may substitute a different token account or mint while keeping the interface looking plausible. The program should derive or verify canonical addresses and check account ownership, mint, authority, and state before changing balances or recording a receipt.
FIELD NOTE 04
Model program-specific attacks
Turn the intended action into an invariant table: precondition, state change, postcondition, and failure case. Check for missing signer checks, unchecked arithmetic, stale or duplicate state, account substitution, unsafe close or reinitialization paths, and assumptions about instruction order. For a deposit, test a wrong mint, wrong vault, unrelated authority, repeated receipt, and insufficient balance. For a withdrawal, test a substituted destination and a forged amount. Include the exact attacker capability and the protected asset in each scenario so the test demonstrates a real boundary.
FIELD NOTE 05
Follow cross-program calls
A cross-program invocation lets one program call another. The callee receives only the signer and writable privileges passed by its caller; it cannot escalate them. `invoke_signed` lets the calling program add signer privilege for a PDA derived from that program ID and the supplied seeds. This authority is narrow but powerful: validate the intended callee program ID, each forwarded account, and the exact PDA seeds before invoking it. Record every CPI edge and expected effect. Atomicity does not make an incorrect authorization safe: a malicious but valid instruction can still commit a harmful result.
FIELD NOTE 06
Follow one attack from input to proof
Suppose a vault accepts a deposit for mint M into vault account V, controlled by authority PDA A. A caller can submit arbitrary public account addresses and can sign for their own wallet, but cannot sign for A. The attack path is to substitute a token account with the same display symbol but a different mint, or to redirect a withdrawal to a different writable destination. The program must establish the relationships on chain: the account has the expected token-program owner, its mint is M, its token authority is the expected owner or PDA, the vault address is canonical for this vault, and the amount and state transition satisfy the instruction invariant. Reject untrusted CPI targets and unexpected forwarded privileges. Test each mutation with valid-looking accounts and assert both the expected rejection and unchanged protected balances and receipt state. These tests show the local program rejected the case; they do not establish which bytes or upgrade authority are live on Mainnet.
FIELD NOTE 07
Include runtime and operational dependencies
Threats include more than program code. Consider upgrade authority, frontend and wallet behavior, RPC providers, indexers, price oracles, token extensions, metadata storage, and release tooling. A compromised upgrade authority can change the code users interact with; an RPC provider can return stale or incomplete observations to an application. Record which facts are verified on chain and which depend on a service. Separate availability failures from integrity failures, and define a pause or fallback only when the actual architecture supports it.
FIELD NOTE 08
Rank risks and demand evidence
Rank each scenario by plausible likelihood, impact, affected users, and detectability. Then connect the mitigation to evidence: a negative program test, a property test, a local-validator run, an authority inspection, an alert rehearsal, or an independently verified transaction. State what the evidence does not establish. A unit test cannot prove deployed program identity; a written policy cannot prove that an operator can pause issuance. Keep open risks, owners, and release decisions visible instead of turning assumptions into security claims.
MAKE THE CONNECTION
A detail worth keeping
For a vault protocol, write invariants for deposit, withdrawal, token mint, vault authority, and receipt uniqueness. Then build an attack tree for a user who can submit arbitrary account addresses but cannot sign for the program’s PDA. Test whether the on-chain checks stop each path.
Work through an example
Review the same design under an upgrade-authority compromise and an RPC outage. These threats need different controls: account constraints cannot contain a malicious upgrade, and an RPC timeout is not proof that a submitted transaction failed. Record the authority or observation that resolves each uncertainty.
Threat-model a fictional token vault. Submit an account and authority map, attacker-capability table, five explicit invariants, one traced account-substitution attack, a CPI privilege map, negative tests that assert unchanged protected state, an external-dependency scenario, and a residual-risk register with owners and evidence. Use fictional addresses and no wallet keys or live funds.
GUIDED PRACTICE · EXPERT
Do the work, one step at a time
Use fictional addresses and disposable test data. Do not enter a recovery phrase or private key. Unless a lesson explicitly says “read-only Devnet,” use paper or a local test and do not connect to a public network.
- Choose a fictional vault, escrow, staking pool, or credential program and draw its accounts and authorities.
- Trace one valid instruction from wallet signature through program checks to changed account state.
- Create five account-substitution or authorization attacks and name the invariant each targets.
- Write a test and expected unchanged state for every rejected attack.
- Separate local-test evidence from deployment, RPC, upgrade-authority, and incident-response evidence.
Before you move on, check your reasoning
- Choose a protocol and map its assets, accounts, signers, and program boundaries.
- Write attacker paths as broken invariants, then pair each high-impact path with a negative test.
- Record residual risks and the operational or deployment evidence still needed before release.
OPEN SELF-CHECK · UNGRADED
Pause and test your reasoning
Two findings have the same likelihood: one exposes a high-value authority used by many users; the other affects a rarely used cosmetic field. How should you prioritize?
- Rank the cosmetic issue first because it has fewer lines of code.
- Compare impact, exposure, assets, existing controls, and realistic exploitation paths before assigning priority.
- Prioritize whichever issue was reported most recently.
Reveal one best answer and its explanation
One best answer: Compare impact, exposure, assets, existing controls, and realistic exploitation paths before assigning priority.
Threat priority comes from a system-specific risk model, not line count, novelty, or finding frequency alone. Record the affected asset, attacker capability, reachable path, impact, controls, residual risk, and owner.
Sources: Sealevel Attacks ↗ · Account Constraints ↗
This practice is not scored, saved, or part of a certificate. Account-based lesson checkpoints and level exams remain separate.
Scored checkpoints and level exams are online and require a free account. They are not included in this pack.
READ THE SOURCE
Go deeper in the official docs
Reviewed on 2026-09-29. Protocol documentation can change; check the linked page’s current version when you reconnect.