Skip to main content
Sigvex

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.

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. an account-validation framework 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)?;

References