Security
Security: the list of known attacks
The attacks that show up in every audit, and which constraint closes each one.
The ones that show up in every audit. Anchor covers most of them if you use its types; in native Rust you do them by hand.
| Attack | What it is | Mitigation |
|---|---|---|
| Missing signer check | Anyone runs an instruction that should require a signature | Signer<'info> plus has_one / address: signing proves who they are, not that they are allowed |
| Missing owner check | An account that does not belong to your program gets read | Account<'info, T> checks the owner |
| Type cosplay | One account impersonates another of the same size | Discriminator (Anchor does it for you) |
| Account data matching | A "valid" account that is not the expected one | has_one, constraint |
| Arbitrary CPI | A program gets invoked that is not the one you think | Verify the program address; Anchor's CPI modules |
| Bump seed canonicalization | A PDA with a non-canonical bump | find_program_address; bump in Anchor |
| Seed collisions / PDA sharing | Two things map to the same PDA | A distinct seed prefix per account type |
| Duplicate mutable accounts | The same account passed twice as mutable | constraint = a.key() != b.key() |
| Closing accounts | A "closed" account that comes back to life | The close constraint; never by hand |
| Reinitialization | An already-initialised account gets initialised again | init (not init_if_needed without checks) |
| Insecure initialization | Anyone initialises global state | Restrict to the upgrade authority |
| Overflow / underflow | Silent arithmetic | checked_*, overflow-checks = true |
| Loss of precision | Rounding in the attacker's favour | Fixed-point; multiply before dividing |
| Account reloading | Stale state after a CPI | reload() |
| Frontrunning | Someone gets ahead of your transaction | expected_price / slippage |
| Remaining accounts | Extra accounts left unvalidated | Validate owner, discriminator and data of each one |
| Authority transfer | Authority gets transferred to the wrong address | Two steps: nominate and accept |
| Realloc | Old data when growing an account | realloc::zero = true |
| Unvalidated oracle | Settling on a stale price, another feed, or a huge confidence interval | Allowlist feed and program ID; max_age; reject high confidence |
| Fake mint / Token-2022 | A "USDC" that is not USDC, or an extension that changes the transfer | Mint + token program per cluster; allowlist of extensions |
Before mainnet (not in the hackathon): audit, bug bounty, upgrade authority in a Squads multisig, verifiable build.