◂ labs
TIER 1 · THE ACCOUNT MODEL · 2-owner-checks
OWNER CHECKS
Any program can create an account with any bytes in it. If you deserialize an AccountInfo without checking `account.owner == expected_program`, an attacker crafts a fake account that parses perfectly and drains the vault.
seen in the wild
Owner-check bypass = the "fake account" primitive behind most pre-Anchor exploits; Anchor `Account<T>` does it for you — AccountInfo never does.
rust · anchor
use anchor_lang::prelude::*;
use anchor_lang::solana_program::program_error::ProgramError;
use anchor_lang::solana_program::program_pack::Pack;
use spl_token::state::Account as SplTokenAccount;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod owner_checks_insecure {
use super::*;
pub fn log_message(ctx: Context<LogMessage>) -> ProgramResult {
let token = SplTokenAccount::unpack(&ctx.accounts.token.data.borrow())?;
if ctx.accounts.authority.key != &token.owner {
return Err(ProgramError::InvalidAccountData);
}
msg!("Your account balance is: {}", token.amount);
Ok(())
}
}
#[derive(Accounts)]
pub struct LogMessage<'info> {
token: AccountInfo<'info>,
authority: Signer<'info>,
}
next labTYPE COSPLAY ▸