Summary
Detect PDAs that are derived with one seed tuple/bump in a program but used as a signer/owner in a CPI with a different seed ordering, missing seeds, or mismatched bump.
Related to #3
Why it matters
Cross-program invocations (CPIs) can silently accept inconsistent PDA derivations, leading to accounts that verify in one place but not another. This can cause signing failures or unintended signer authority, especially in security-critical protocols.
Proposed Approach
• Track Pubkey::find_program_address / find_program_address_seeds calls and Anchor #[account(seeds=..., bump)] attributes.
• Build a “seed signature” (ordered seed list + bump + program_id) for each PDA.
• On any CPI site, verify that with_signer(&[...]) matches the stored seed signature for that PDA.
• Allow intentional exceptions via #[allow(pda_inconsistent_signer)].
Examples
Flag:
#[account(seeds=[b"pool", authority.key().as_ref()], bump)]
pub pool: Account<'info, Pool>;
// later in CPI
let signer_seeds = &[b"pool".as_ref(), &[bump]]; // missing authority seed
invoke_signed(..., &[signer_seeds]);
Pass:
let seeds = &[b"pool".as_ref(), authority.key().as_ref(), &[bump]];
invoke_signed(..., &[seeds]);
Summary
Detect PDAs that are derived with one seed tuple/bump in a program but used as a signer/owner in a CPI with a different seed ordering, missing seeds, or mismatched bump.
Related to #3
Why it matters
Cross-program invocations (CPIs) can silently accept inconsistent PDA derivations, leading to accounts that verify in one place but not another. This can cause signing failures or unintended signer authority, especially in security-critical protocols.
Proposed Approach
Examples
Flag:
Pass: