Frozen Account Operations Remediation
How to fix missing frozen state checks before token operations.
Frozen Account Operations Remediation
Overview
Related Detector: Frozen Account Operations
Token operations on frozen accounts fail at the SPL Token runtime level. Adding explicit frozen state checks improves error messages and prevents unexpected control flow.
Recommended Fix
Before (Vulnerable)
// No frozen check -- SPL Token rejects with generic error
let ix = spl_token::instruction::transfer(...)?;
invoke(&ix, accounts)?;
After (Fixed)
// Explicit frozen check with clear error message
let token_data = Account::unpack(&source.data.borrow())?;
if token_data.state == AccountState::Frozen {
msg!("Token account is frozen, cannot transfer");
return Err(ProgramError::Custom(ErrorCode::AccountFrozen as u32));
}
let ix = spl_token::instruction::transfer(...)?;
invoke(&ix, accounts)?;
Alternative Mitigations
1. Anchor constraint
#[account(
mut,
constraint = token_account.state != AccountState::Frozen @ ErrorCode::AccountFrozen
)]
pub token_account: Account<'info, TokenAccount>,
2. Helper function
Create a reusable validation function:
fn require_not_frozen(account: &AccountInfo) -> ProgramResult {
let data = Account::unpack(&account.data.borrow())?;
if data.state == AccountState::Frozen {
return Err(ProgramError::Custom(ErrorCode::AccountFrozen as u32));
}
Ok(())
}
Common Mistakes
Mistake 1: Only checking source, not destination
// INCOMPLETE: destination may also be frozen
require_not_frozen(source)?;
// Missing: require_not_frozen(destination)?;