Passing Accounts to CPIs
CPI account lists must mirror the callee's expected order, signer flags, and writability. Your program is responsible for not elevating privileges beyond what the outer transaction intended.
Recipe
let metas = vec![
AccountMeta::new(source, false),
AccountMeta::new(dest, false),
AccountMeta::new_readonly(authority, true),
];When to reach for this:
- Building custom CPI to SPL programs.
- Auditing privilege escalation.
- Composing multiple CPIs in one instruction.
Working Example
// Validate source writable only if caller intended mutation
if !source.is_writable { return Err(ProgramError::InvalidAccountData); }
let ix = spl_token::instruction::transfer(...)?;
invoke(&ix, &[source.clone(), dest.clone(), authority.clone(), token_program.clone()])?;What this demonstrates:
- Explicit writable check before CPI.
- Authority marked signer in metas.
- Token program account included.
Deep Dive
Privilege Escalation
Passing writable + signer to callee when outer tx did not authorize is a critical bug.
Ordering
Follow callee source definitions (spl-token, system).
Rust Notes
// AccountMeta::new_readonly(key, is_signer)Gotchas
- Extra writable accounts - Callee mutates attacker account.. Fix: Least privilege metas.
- Missing program account - CPI fails.. Fix: Include callee program id account.
- Signer escalation - Marking non-signer as signer.. Fix: Match outer tx flags unless PDA.
- Account order swap - Wrong token accounts.. Fix: Copy from spl helpers.
- Unchecked duplicate - Same account twice.. Fix: Reject if unsafe.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| spl instruction builders | Correct metas | Custom programs |
| Anchor cpi module | Generated | Manual |
| Codama clients | Off-chain only | On-chain still manual |
FAQs
Who checks metas?
Callee program re-validates.
Roof signer?
Outer tx signers + invoke_signed only.
Readonly mut attempt?
Callee errors.
ALT addresses?
Resolved before runtime.
Many accounts?
Use remaining accounts pattern in Anchor.
CPI to your program?
Reentrancy considerations.
Program writable?
Usually readonly program account.
Sysvar in CPI?
If callee requires.
Token multisig?
Extra signer accounts.
Sim logs?
Show callee program id.
AccountInfo clone cost?
Cheap.
Test wrong order?
LiteSVM negative tests.
Related
- Manual Account Validation - Validation
- CPI to SPL Token - Token layout
- Reentrancy & Safety - CPI callbacks
Stack versions: This page was written for Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, and LiteSVM 0.6.x.