◂ labs
TIER 2 · CPI & PDAs · 5-arbitrary-cpi

ARBITRARY CPI

`invoke`/`invoke_signed` trust the program_id account passed in. If it isn't pinned to an expected address, the attacker supplies their own program — which happily reports "transfer succeeded" while keeping the tokens.

seen in the wild
The pack CONFIRMED this class on sealevel-attacks: invoke with arbitrary program id + signer-bit propagation = real drain.
rust · anchor
use anchor_lang::prelude::*;
use anchor_lang::solana_program;

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

#[program]
pub mod arbitrary_cpi_insecure {
    use super::*;

    pub fn cpi(ctx: Context<Cpi>, amount: u64) -> ProgramResult {
        solana_program::program::invoke(
            &spl_token::instruction::transfer(
                ctx.accounts.token_program.key,
                ctx.accounts.source.key,
                ctx.accounts.destination.key,
                ctx.accounts.authority.key,
                &[],
                amount,
            )?,
            &[
                ctx.accounts.source.clone(),
                ctx.accounts.destination.clone(),
                ctx.accounts.authority.clone(),
            ],
        )
    }
}

#[derive(Accounts)]
pub struct Cpi<'info> {
    source: AccountInfo<'info>,
    destination: AccountInfo<'info>,
    authority: AccountInfo<'info>,
    token_program: AccountInfo<'info>,
}
▸ the pack already hunted this class — watch the live feed of run_1789547662_fca40c