Skip to content

Rule: PDA seeds/signing consistency across CPIs #4

@Cass402

Description

@Cass402

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]);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions