Skip to main content
Sigvex

PDA Ownership Validation Remediation

How to fix PDA usage without ownership validation.

PDA Ownership Validation Remediation

Overview

Related Detector: PDA Ownership Validation

PDA ownership vulnerabilities allow attackers to substitute accounts owned by other programs at expected PDA addresses. The fix is to always verify account.owner == program_id before reading or writing PDA data.

Before (Vulnerable)

let vault = &accounts[0]; // No owner check
let data = vault.data.borrow();

After (Fixed)

let vault = &accounts[0];
if vault.owner != program_id {
    return Err(ProgramError::IllegalOwner);
}
let data = vault.data.borrow();

Alternative Mitigations

1. Anchor Account type

#[account(seeds = [b"vault"], bump)]
pub vault: Account<'info, Vault>, // Owner validated automatically

2. Combined address and owner check

let (expected_pda, _) = Pubkey::find_program_address(&[b"vault"], program_id);
if vault.key != &expected_pda || vault.owner != program_id {
    return Err(ProgramError::InvalidAccountData);
}

Common Mistakes

Mistake 1: Checking address but not owner

// INSUFFICIENT: correct address but wrong owner
if vault.key != &expected_pda { return Err(...); }
// Missing: vault.owner check

Mistake 2: Using UncheckedAccount in Anchor without manual validation

// WRONG: UncheckedAccount skips owner validation
pub vault: UncheckedAccount<'info>,
// Must add: #[account(constraint = vault.owner == program_id)]

References