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.
Optional reading history is saved only in this browser. It is not a scored checkpoint or exam result.
In this lesson8 field notes · practice · sources · checkpoint
Read a text version of this diagram
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
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.
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.
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.
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.
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.
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.
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.
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.
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. Most exercises work on paper or with a local test; only a lesson that clearly says “read-only Devnet” makes a public network request.
- 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?
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.
Never enter a recovery phrase or private key into a learning site or lesson exercise.
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 as you use this material.
OPEN LEARNING
Keep learning at your own pace.
This lesson, its guided practice, and all six course lessons are open to everyone. Account-based checkpoints, exams, and saved progress will open when free accounts are ready.
Continue to the next lesson ↗