> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/solana-foundation/anchor/llms.txt
> Use this file to discover all available pages before exploring further.

# Security Best Practices

> Learn about account constraints, validation, and common security exploits to avoid in Anchor programs

Security is paramount when building Solana programs. Anchor provides powerful tools to help you write secure code, but understanding common vulnerabilities and best practices is essential.

## Account Validation

### Always Validate Account Ownership

One of the most critical security checks is verifying that accounts are owned by the expected program:

```rust theme={null}
#[derive(Accounts)]
pub struct UpdateData<'info> {
    // Anchor automatically checks that Account<'info, MyAccount>
    // is owned by the current program
    #[account(mut)]
    pub my_account: Account<'info, MyAccount>,
}
```

The `Account<'info, T>` type automatically verifies:

* `account.owner == T::owner()`
* Account is not owned by SystemProgram with 0 lamports
* Account discriminator matches the expected type

### Validate Signers

Always verify that accounts expected to authorize operations have signed:

```rust theme={null}
#[derive(Accounts)]
pub struct Transfer<'info> {
    #[account(mut, has_one = authority)]
    pub vault: Account<'info, Vault>,
    // Use Signer type to ensure the account signed
    pub authority: Signer<'info>,
}
```

**Bad - Using AccountInfo without verification:**

```rust theme={null}
pub authority: AccountInfo<'info>, // ❌ No signer check!
```

**Good - Using Signer type:**

```rust theme={null}
pub authority: Signer<'info>, // ✅ Automatically checked
```

### Use has\_one Constraint

The `has_one` constraint verifies account relationships:

```rust theme={null}
#[account]
pub struct Vault {
    pub authority: Pubkey,
    pub balance: u64,
}

#[derive(Accounts)]
pub struct Withdraw<'info> {
    #[account(
        mut,
        has_one = authority @ ErrorCode::Unauthorized
    )]
    pub vault: Account<'info, Vault>,
    pub authority: Signer<'info>,
}
```

This checks that `vault.authority == authority.key()`.

## Common Security Vulnerabilities

### 1. Missing Signer Checks

**Vulnerable:**

```rust theme={null}
pub fn withdraw(ctx: Context<Withdraw>, amount: u64) -> Result<()> {
    // ❌ No check that authority signed!
    ctx.accounts.vault.balance -= amount;
    Ok(())
}

#[derive(Accounts)]
pub struct Withdraw<'info> {
    #[account(mut)]
    pub vault: Account<'info, Vault>,
    pub authority: AccountInfo<'info>, // ❌ Should be Signer
}
```

**Secure:**

```rust theme={null}
#[derive(Accounts)]
pub struct Withdraw<'info> {
    #[account(
        mut,
        has_one = authority
    )]
    pub vault: Account<'info, Vault>,
    pub authority: Signer<'info>, // ✅ Enforces signature
}
```

### 2. Missing Ownership Checks

**Vulnerable:**

```rust theme={null}
#[derive(Accounts)]
pub struct Attack<'info> {
    /// CHECK: ❌ This is dangerous! No ownership check
    pub fake_account: AccountInfo<'info>,
}
```

An attacker could pass an account from a different program.

**Secure:**

```rust theme={null}
#[derive(Accounts)]
pub struct Secure<'info> {
    // ✅ Automatically checks ownership
    pub real_account: Account<'info, MyAccount>,
}
```

### 3. Arithmetic Overflow/Underflow

**Vulnerable:**

```rust theme={null}
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
    ctx.accounts.vault.balance += amount; // ❌ Could overflow
    Ok(())
}
```

**Secure:**

```rust theme={null}
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
    ctx.accounts.vault.balance = ctx.accounts.vault.balance
        .checked_add(amount)
        .ok_or(ErrorCode::Overflow)?; // ✅ Safe arithmetic
    Ok(())
}
```

### 4. Reinitialization Attacks

**Vulnerable:**

```rust theme={null}
#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = user, space = 8 + 32)]
    pub account: Account<'info, MyAccount>, // ❌ Could reinitialize
}
```

If an account already exists, `init` will fail, but without proper checks, you might allow reinitialization.

**Secure - Use init only once:**

```rust theme={null}
#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(
        init,
        payer = user,
        space = 8 + MyAccount::INIT_SPACE
    )]
    pub account: Account<'info, MyAccount>, // ✅ Fails if exists
}

// Or for updates:
#[derive(Accounts)]
pub struct Update<'info> {
    #[account(mut)]
    pub account: Account<'info, MyAccount>, // ✅ Requires existing account
}
```

### 5. PDA Validation

**Vulnerable:**

```rust theme={null}
#[derive(Accounts)]
pub struct UsePda<'info> {
    /// CHECK: ❌ Not verifying PDA derivation
    pub pda: AccountInfo<'info>,
}
```

**Secure:**

```rust theme={null}
#[derive(Accounts)]
pub struct UsePda<'info> {
    #[account(
        seeds = [b"vault", authority.key().as_ref()],
        bump
    )]
    pub pda: Account<'info, Vault>, // ✅ Verifies correct PDA
    pub authority: Signer<'info>,
}
```

### 6. Account Closing Vulnerabilities

**Vulnerable - Revival attacks:**

```rust theme={null}
pub fn close_account(ctx: Context<Close>) -> Result<()> {
    // ❌ Manual closing is dangerous
    **ctx.accounts.account.to_account_info().lamports.borrow_mut() = 0;
    Ok(())
}
```

**Secure:**

```rust theme={null}
#[derive(Accounts)]
pub struct Close<'info> {
    #[account(
        mut,
        close = authority, // ✅ Anchor handles closing safely
        has_one = authority
    )]
    pub account: Account<'info, MyAccount>,
    #[account(mut)]
    pub authority: Signer<'info>,
}
```

### 7. Duplicate Mutable Accounts

**Vulnerable:**

```rust theme={null}
#[derive(Accounts)]
pub struct DangerousAccounts<'info> {
    #[account(mut)]
    pub account1: Account<'info, MyAccount>,
    #[account(mut)]
    pub account2: Account<'info, MyAccount>, // ❌ Could be same as account1
}
```

By default, Anchor prevents this. To allow it intentionally:

```rust theme={null}
#[derive(Accounts)]
pub struct AllowDuplicates<'info> {
    #[account(mut)]
    pub account1: Account<'info, MyAccount>,
    #[account(mut, dup)] // ✅ Explicitly allow duplicates
    pub account2: Account<'info, MyAccount>,
}
```

## Security Checklist

Before deploying your program, verify:

* [ ] All authority accounts use `Signer<'info>` type
* [ ] All account relationships validated with `has_one` or `constraint`
* [ ] All PDAs validated with `seeds` and `bump`
* [ ] All arithmetic uses checked operations
* [ ] All accounts use proper types (`Account`, `Signer`, etc., not raw `AccountInfo`)
* [ ] Account discriminators checked (automatic with `Account` type)
* [ ] Close constraints used instead of manual closing
* [ ] No unintentional duplicate mutable accounts
* [ ] All `/// CHECK:` comments explain why validation is skipped
* [ ] Token amounts and balances validated
* [ ] Time-based logic uses `Clock` sysvar correctly

## Complete Secure Example

Here's a secure token vault implementation:

```rust theme={null}
use anchor_lang::prelude::*;
use anchor_spl::token::{self, Token, TokenAccount, Transfer};

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

#[program]
pub mod secure_vault {
    use super::*;

    pub fn initialize(
        ctx: Context<Initialize>,
        vault_bump: u8,
    ) -> Result<()> {
        let vault = &mut ctx.accounts.vault;
        vault.authority = ctx.accounts.authority.key();
        vault.token_account = ctx.accounts.vault_token_account.key();
        vault.bump = vault_bump;
        vault.total_deposited = 0;
        
        msg!("Vault initialized");
        Ok(())
    }

    pub fn deposit(
        ctx: Context<Deposit>,
        amount: u64,
    ) -> Result<()> {
        require!(amount > 0, ErrorCode::InvalidAmount);
        
        let vault = &mut ctx.accounts.vault;
        
        // Safe arithmetic
        vault.total_deposited = vault.total_deposited
            .checked_add(amount)
            .ok_or(ErrorCode::Overflow)?;
        
        // Transfer tokens via CPI
        let cpi_accounts = Transfer {
            from: ctx.accounts.user_token_account.to_account_info(),
            to: ctx.accounts.vault_token_account.to_account_info(),
            authority: ctx.accounts.user.to_account_info(),
        };
        let cpi_program = ctx.accounts.token_program.to_account_info();
        let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);
        
        token::transfer(cpi_ctx, amount)?;
        
        msg!("Deposited {} tokens", amount);
        Ok(())
    }

    pub fn withdraw(
        ctx: Context<Withdraw>,
        amount: u64,
    ) -> Result<()> {
        require!(amount > 0, ErrorCode::InvalidAmount);
        
        let vault = &mut ctx.accounts.vault;
        let available = ctx.accounts.vault_token_account.amount;
        
        require!(amount <= available, ErrorCode::InsufficientFunds);
        
        // Safe arithmetic
        vault.total_deposited = vault.total_deposited
            .checked_sub(amount)
            .ok_or(ErrorCode::Underflow)?;
        
        // PDA signing
        let authority_seeds = &[
            b"vault",
            vault.authority.as_ref(),
            &[vault.bump],
        ];
        let signer_seeds = &[&authority_seeds[..]];
        
        let cpi_accounts = Transfer {
            from: ctx.accounts.vault_token_account.to_account_info(),
            to: ctx.accounts.user_token_account.to_account_info(),
            authority: ctx.accounts.vault_authority.to_account_info(),
        };
        let cpi_program = ctx.accounts.token_program.to_account_info();
        let cpi_ctx = CpiContext::new_with_signer(
            cpi_program,
            cpi_accounts,
            signer_seeds,
        );
        
        token::transfer(cpi_ctx, amount)?;
        
        msg!("Withdrew {} tokens", amount);
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(
        init,
        payer = authority,
        space = 8 + Vault::INIT_SPACE,
        seeds = [b"vault", authority.key().as_ref()],
        bump
    )]
    pub vault: Account<'info, Vault>,
    
    #[account(
        constraint = vault_token_account.owner == vault_authority.key()
    )]
    pub vault_token_account: Account<'info, TokenAccount>,
    
    /// CHECK: PDA authority for vault
    #[account(
        seeds = [b"vault", authority.key().as_ref()],
        bump
    )]
    pub vault_authority: AccountInfo<'info>,
    
    #[account(mut)]
    pub authority: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct Deposit<'info> {
    #[account(mut)]
    pub vault: Account<'info, Vault>,
    
    #[account(
        mut,
        constraint = vault_token_account.key() == vault.token_account
    )]
    pub vault_token_account: Account<'info, TokenAccount>,
    
    #[account(mut)]
    pub user_token_account: Account<'info, TokenAccount>,
    
    pub user: Signer<'info>,
    pub token_program: Program<'info, Token>,
}

#[derive(Accounts)]
pub struct Withdraw<'info> {
    #[account(
        mut,
        has_one = authority @ ErrorCode::Unauthorized,
        has_one = token_account @ ErrorCode::InvalidTokenAccount
    )]
    pub vault: Account<'info, Vault>,
    
    #[account(
        mut,
        constraint = vault_token_account.key() == vault.token_account
    )]
    pub vault_token_account: Account<'info, TokenAccount>,
    
    /// CHECK: PDA authority validated via seeds
    #[account(
        seeds = [b"vault", authority.key().as_ref()],
        bump = vault.bump
    )]
    pub vault_authority: AccountInfo<'info>,
    
    #[account(mut)]
    pub user_token_account: Account<'info, TokenAccount>,
    
    pub authority: Signer<'info>,
    pub token_program: Program<'info, Token>,
}

#[account]
#[derive(InitSpace)]
pub struct Vault {
    pub authority: Pubkey,
    pub token_account: Pubkey,
    pub total_deposited: u64,
    pub bump: u8,
}

#[error_code]
pub enum ErrorCode {
    #[msg("Amount must be greater than zero")]
    InvalidAmount,
    #[msg("Insufficient funds")]
    InsufficientFunds,
    #[msg("Unauthorized access")]
    Unauthorized,
    #[msg("Invalid token account")]
    InvalidTokenAccount,
    #[msg("Arithmetic overflow")]
    Overflow,
    #[msg("Arithmetic underflow")]
    Underflow,
}
```

## Additional Security Resources

* [Solana Security Best Practices](https://github.com/coral-xyz/sealevel-attacks)
* [Anchor Account Constraints](https://docs.rs/anchor-lang/latest/anchor_lang/derive.Accounts.html)
* [Neodyme Security Blog](https://blog.neodyme.io/)
* [Soteria Security Tool](https://github.com/soteria-security/soteria)

## Auditing

Before deploying to mainnet:

1. **Self-review**: Go through this security checklist
2. **Peer review**: Have other developers review your code
3. **Testing**: Write comprehensive tests including edge cases
4. **Professional audit**: Consider hiring a security firm for critical programs
5. **Bug bounty**: Run a bug bounty program for additional security

<Callout type="warning">
  Security is an ongoing process. Stay updated on new vulnerabilities and best practices in the Solana ecosystem.
</Callout>

## Related Resources

* [Account Constraints Reference](/api/rust/account-constraints)
* [Account Types Reference](/api/rust/account-types)
* [Error Handling](/guides/errors)
