A hands-on educational resource for Solana developers to learn common smart contract vulnerabilities through working code and exploit tests.
Each pattern includes:
- Anchor implementation — Vulnerable + secure versions using the Anchor framework
- Pinocchio implementation — Same patterns using low-level Pinocchio for comparison
- Mollusk exploit tests — Proves the vulnerability is real and the fix works
| # | Pattern | Description | Real-World Reference |
|---|---|---|---|
| 1 | Missing Signer Check | Failing to verify transaction signatures | Common in early Solana programs |
| 2 | Missing Owner Check | Trusting account data without verifying ownership | Wormhole ($326M) |
| 3 | Integer Overflow | Arithmetic that wraps instead of failing | Multiple token exploits |
| 4 | Re-initialization Attack | Allowing accounts to be initialized twice | DeFi protocol takeovers |
| 5 | PDA Bump Canonicalization | Accepting non-canonical bumps for PDAs | PDA uniqueness bypasses |
| 6 | Type Cosplay | Passing wrong account type with same layout | Admin privilege escalation |
- Rust 1.75+
- Solana CLI 2.1+
- Anchor CLI 0.31+
# Build all Anchor programs
for dir in patterns/*/anchor; do
cargo build-sbf --manifest-path "$dir/Cargo.toml"
done
# Build all Pinocchio programs
for dir in patterns/*/pinocchio; do
cargo build-sbf --manifest-path "$dir/Cargo.toml"
done# Run all tests
SBF_OUT_DIR=target/deploy cargo test -- --nocapture
# Run tests for a specific pattern
SBF_OUT_DIR=target/deploy cargo test -p test-missing-signer -- --nocapture
SBF_OUT_DIR=target/deploy cargo test -p test-missing-owner -- --nocapture
SBF_OUT_DIR=target/deploy cargo test -p test-integer-overflow -- --nocapture
SBF_OUT_DIR=target/deploy cargo test -p test-reinitialization -- --nocapture
SBF_OUT_DIR=target/deploy cargo test -p test-pda-bump -- --nocapture
SBF_OUT_DIR=target/deploy cargo test -p test-type-cosplay -- --nocapturesolana-security-patterns/
├── patterns/
│ ├── 01-missing-signer-check/
│ │ ├── anchor/ # Anchor program (vulnerable + secure)
│ │ ├── pinocchio/ # Pinocchio program (vulnerable + secure)
│ │ ├── tests/ # Mollusk exploit tests
│ │ └── README.md # Pattern documentation
│ ├── 02-missing-owner-check/
│ │ └── ...
│ └── ...
├── Cargo.toml # Workspace configuration
├── DEEP_DIVE.md # In-depth vulnerability analysis
└── README.md
Tests use Mollusk, Anza's lightweight SVM simulator. Mollusk runs Solana programs without a full validator, making tests fast and deterministic.
Each test file demonstrates:
- Exploit test — Shows the vulnerability being exploited
- Secure rejection test — Shows the fix blocking the attack
- Sanity test — Confirms legitimate operations still work
For learning:
- Read a pattern's README to understand the vulnerability
- Examine the Anchor code (
lib.rs) — compare vulnerable vs secure - Run the exploit tests to see the attack succeed and fail
- Apply the lessons to your own code
For auditing:
- Use these patterns as a checklist when reviewing Solana programs
- The test structure shows how to write exploit PoCs
For teaching:
- Each pattern is self-contained and can be presented independently
- The vulnerable/secure side-by-side comparison is designed for clarity
| Pattern | One-Line Fix |
|---|---|
| Missing Signer | Use Signer<'info> not AccountInfo |
| Missing Owner | Use Account<T> not AccountInfo |
| Integer Overflow | Use checked_add/sub/mul/div |
| Re-initialization | Use init constraint or check is_initialized |
| PDA Bump | Use find_program_address, never accept bump as input |
| Type Cosplay | Use Account<T> to enforce discriminator checks |
MIT