This report was generated by Rust Solana Analyzer, a static analysis tool for Solana smart contracts. This report is not a substitute for manual audit or security review. It should not be relied upon for any purpose other than to assist in the identification of potential security vulnerabilities.
| Key | Value |
|---|---|
| .rs Files | 1 |
| Total Issues | 11 |
| Filepath | Issues |
|---|---|
| lib.rs | 11 |
| Total | 11 |
| Category | No. of Issues |
|---|---|
| High | 2 |
| Medium | 3 |
| Low | 6 |
| Informational | 0 |
Detects Anchor account fields that may need signer verification
1 Found Instance
-
Found in lib.rs [Line: 50]
#[derive(Accounts)] pub struct VulnerableDuplicateMutable<'info> { /// CHECK: This account is vulnerable to duplicate account attacks #[account(mut)] pub account1: AccountInfo<'info>, /// CHECK: This account is vulnerable to duplicate account attacks #[account(mut)] pub account2: AccountInfo<'info>, pub authority: Signer<'info>, }
Recommendations
- Add signer constraint to account fields that should be signed: #[account(signer)]
- Use Signer<'info> type for accounts that must be signers of the transaction
- Verify account ownership and signer status in instruction logic when needed
- Consider using #[account(constraint = account.key() == signer.key())] for explicit signer validation
- Review all account fields to ensure proper authorization and access control
Detects Anchor account fields that may need signer verification
1 Found Instance
-
Found in lib.rs [Line: 85]
#[derive(Accounts)] pub struct TransferFunds<'info> { /// CHECK: The source account != destination account #[account( mut, owner = system_program::ID, constraint = source.key() != destination.key() @ ErrorCode::SameAccount )] pub source: AccountInfo<'info>, /// CHECK: The destination account is verified by the owner constraint #[account( mut, owner = system_program::ID )] pub destination: AccountInfo<'info>, pub authority: Signer<'info>, pub system_program: Program<'info, System>, }
Recommendations
- Add signer constraint to account fields that should be signed: #[account(signer)]
- Use Signer<'info> type for accounts that must be signers of the transaction
- Verify account ownership and signer status in instruction logic when needed
- Consider using #[account(constraint = account.key() == signer.key())] for explicit signer validation
- Review all account fields to ensure proper authorization and access control
Detects account structs with multiple mutable references to the same account type, which can lead to unexpected behavior
1 Found Instance
-
Found in lib.rs [Line: 50]
#[derive(Accounts)] pub struct VulnerableDuplicateMutable<'info> { /// CHECK: This account is vulnerable to duplicate account attacks #[account(mut)] pub account1: AccountInfo<'info>, /// CHECK: This account is vulnerable to duplicate account attacks #[account(mut)] pub account2: AccountInfo<'info>, pub authority: Signer<'info>, }
Recommendations
- Add constraints to ensure accounts are different: #[account(constraint = account1.key() != account2.key())]
- Use a single mutable account reference instead of multiple ones when possible
- Implement explicit validation in your instruction handler to prevent the same account being passed multiple times
- Consider using Anchor's constraint system to enforce account uniqueness at the framework level
Detects structs that properly implement owner checks for account validation
1 Found Instance
-
Found in lib.rs [Line: 85]
#[derive(Accounts)] pub struct TransferFunds<'info> { /// CHECK: The source account != destination account #[account( mut, owner = system_program::ID, constraint = source.key() != destination.key() @ ErrorCode::SameAccount )] pub source: AccountInfo<'info>, /// CHECK: The destination account is verified by the owner constraint #[account( mut, owner = system_program::ID )] pub destination: AccountInfo<'info>, pub authority: Signer<'info>, pub system_program: Program<'info, System>, }
Recommendations
- Add explicit owner validation in your account struct using #[account(constraint = account.owner == expected_owner)] or similar patterns
- Use Anchor's built-in Account<'info, T> wrapper which automatically validates the account owner
- Implement manual owner checks in your instruction handler before processing the account
- Consider using Anchor's #[account(owner = program_id)] constraint for program-owned accounts
Detects division operations without zero verification
1 Found Instance
-
Found in lib.rs [Line: 38]
pub fn vulnerable_division(ctx: Context<Initialize>, divisor: u64) -> Result<()> { //TODO let a = 100; let _result = a / divisor; Ok(()) }
Recommendations
- Add explicit zero checks before division operations: if divisor == 0 { return Err(...) }
- Use checked division methods: checked_div() which returns Option
- Implement proper error handling for division by zero cases
- Consider using safe arithmetic operations provided by Anchor or custom error types
- Validate input parameters at the beginning of instruction handlers
Detects functions that are Anchor program instructions (public functions with Context parameter)
1 Found Instance
-
Found in lib.rs [Line: 38]
pub fn vulnerable_division(ctx: Context<Initialize>, divisor: u64) -> Result<()> { //TODO let a = 100; let _result = a / divisor; Ok(()) }
Recommendations
- Ensure all instruction handlers return Result<()> for proper error handling
- Add proper account validation using constraints in your Context struct
- Consider adding access control checks at the beginning of instruction handlers
- Use #[access_control] attribute for complex authorization logic
- Document instruction parameters and expected account states
Detects functions that are Anchor program instructions (public functions with Context parameter)
1 Found Instance
-
Found in lib.rs [Line: 63]
pub fn vulnerable_duplicate_accounts(ctx: Context<VulnerableDuplicateMutable>) -> Result<()> { **ctx.accounts.account1.lamports.borrow_mut() -= 100; **ctx.accounts.account2.lamports.borrow_mut() += 100; Ok(()) }
Recommendations
- Ensure all instruction handlers return Result<()> for proper error handling
- Add proper account validation using constraints in your Context struct
- Consider adding access control checks at the beginning of instruction handlers
- Use #[access_control] attribute for complex authorization logic
- Document instruction parameters and expected account states
Detects functions that are Anchor program instructions (public functions with Context parameter)
1 Found Instance
-
Found in lib.rs [Line: 18]
pub fn initialize(ctx: Context<Initialize>) -> Result<()> { msg!("Greetings from: {:?}", ctx.program_id); Ok(()) }
Recommendations
- Ensure all instruction handlers return Result<()> for proper error handling
- Add proper account validation using constraints in your Context struct
- Consider adding access control checks at the beginning of instruction handlers
- Use #[access_control] attribute for complex authorization logic
- Document instruction parameters and expected account states
Detects public functions that don't return Result and may fail silently. In Solana contracts, proper error handling is essential for security and debugging.
1 Found Instance
-
Found in lib.rs [Line: 77]
pub fn validate_account_name(name: String) { // This function performs validation but doesn't return Result if name.len() > 32 { panic!("Name too long"); // Bad error handling } println!("Account name is valid: {}", name); }
Recommendations
- Change function return type to Result<T, YourErrorType> to handle potential failures
- Use Anchor's Result<()> for instruction handlers to properly propagate errors
- Implement custom error types using #[error_code] for better error reporting
- Add proper error handling with ? operator or explicit error returns
- Consider using anchor_lang::Result for Anchor-specific error handling
Detects public functions that don't return Result and may fail silently. In Solana contracts, proper error handling is essential for security and debugging.
1 Found Instance
-
Found in lib.rs [Line: 71]
pub fn calculate_fee(amount: u64) -> u64 { // This function could fail but doesn't return Result amount * 5 / 100 // Could panic on overflow }
Recommendations
- Change function return type to Result<T, YourErrorType> to handle potential failures
- Use Anchor's Result<()> for instruction handlers to properly propagate errors
- Implement custom error types using #[error_code] for better error reporting
- Add proper error handling with ? operator or explicit error returns
- Consider using anchor_lang::Result for Anchor-specific error handling
Detects functions that are Anchor program instructions (public functions with Context parameter)
1 Found Instance
-
Found in lib.rs [Line: 23]
pub fn transfer_funds(ctx: Context<TransferFunds>, amount: u64) -> Result<()> { if **ctx.accounts.source.lamports.borrow() < amount { return Err(error!(ErrorCode::InsufficientFunds)); } **ctx.accounts.source.lamports.borrow_mut() -= amount; **ctx.accounts.destination.lamports.borrow_mut() += amount; let x = 200; let y = 2; let _result = x / y; Ok(()) }
Recommendations
- Ensure all instruction handlers return Result<()> for proper error handling
- Add proper account validation using constraints in your Context struct
- Consider adding access control checks at the beginning of instruction handlers
- Use #[access_control] attribute for complex authorization logic
- Document instruction parameters and expected account states