Security & Audits
Best practices for secure Solana program development
Security is paramount in blockchain development. Learn common vulnerabilities, best practices, and how to audit your Solana programs.
Common Vulnerabilities
Signer Authorization
Always verify that required signers are actually signing transactions.
Account Validation
Validate all account owners and data before using them.
Reentrancy
Protect against reentrancy attacks in Cross-Program Invocations.
Data Validation
Sanitize and validate all input data and deserialization.
Security Best Practices
1. Use Anchor's Built-in Security
Anchor provides automatic checks for:
- Account ownership verification
- Signer validation
- Account discriminator checks
- Rent exemption
#[derive(Accounts)]
pub struct SecureInstruction<'info> {
#[account(mut, has_one = authority)]
pub my_account: Account<'info, MyAccount>,
pub authority: Signer<'info>,
}
2. Implement Access Control
pub fn protected_function(ctx: Context<Protected>) -> Result<()> {
require!(
ctx.accounts.user.key() == AUTHORIZED_PUBKEY,
ErrorCode::Unauthorized
);
// Protected logic here
Ok(())
}
3. Validate All Inputs
pub fn transfer(ctx: Context<Transfer>, amount: u64) -> Result<()> {
require!(amount > 0, ErrorCode::InvalidAmount);
require!(amount <= MAX_TRANSFER, ErrorCode::AmountTooLarge);
// Transfer logic
Ok(())
}
4. Use PDA Safely
#[derive(Accounts)]
pub struct UsePDA<'info> {
#[account(
seeds = [b"pda", user.key().as_ref()],
bump,
constraint = pda_account.authority == user.key()
)]
pub pda_account: Account<'info, PDAAccount>,
pub user: Signer<'info>,
}
Security Checklist
Before deploying to mainnet:
- ✓ All accounts properly validated
- ✓ Signer requirements enforced
- ✓ Integer overflow/underflow prevented
- ✓ Rent exemption checked
- ✓ Access controls implemented
- ✓ Error handling comprehensive
- ✓ Testing coverage >90%
- ✓ Fuzzing tests performed
- ✓ External audit completed
Audit Firms & Resources
Testing for Security
Unit Tests
it("Rejects unauthorized access", async () => {
try {
await program.methods
.protectedFunction()
.accounts({
user: unauthorizedUser.publicKey,
})
.signers([unauthorizedUser])
.rpc();
assert.fail("Should have thrown error");
} catch (err) {
assert.ok(err);
}
});
Learn More
- Sealevel Attacks: Common attack vectors
- Anchor Security: Security guide
- Audit Reports: Example audits
Ready to build securely?
Start with our Quickstart Guide and follow best practices throughout development!