Precarious associated-token-account constraints
It was noted during the audit that a few of the instruction contexts had used constraint practices that were considered precarious. Take the TransferVesting
instruction context, which involves a VestingBalance
account, a current and new Vesting
account, and a current and new vester associated token account, as well as a signature of the vester. It is imperative that constraints are present that enforce that the signer owns the vesting TokenAccount
, the associated Vesting
account, and the VestingBalance
account. If any of these constraints are not held, then an attacker might be able to pass a victim's VestingBalance
, rather than their own.
Part of our conclusion that the design of this instruction context was precarious was the pattern repeated throughout the codebase where associated token accounts (ATAs) used their own fields as constraints. This then requires other accounts to step in and provide constraints to tie permissions together.
Here is an example:
#[account(
mut,
associated_token::mint = mint,
associated_token::authority = vester_ta.owner,
associated_token::token_program = token_program
)]
vester_ta: Box<InterfaceAccount<'info, TokenAccount>>,
It is recommended that if an appropriate ATA authority is available it be used as a constraint instead of the ATA itself.