Weak PDA Entropy Remediation
How to fix PDA derivations using weak seed entropy.
Weak PDA Entropy Remediation
Overview
Related Detector: Weak PDA Entropy
Weak PDA entropy enables attackers to predict and pre-compute PDA addresses. The fix is to replace low-entropy seeds (timestamps, small numbers, sequential IDs) with high-entropy sources (public keys, mint addresses).
Recommended Fix
Before (Vulnerable)
let ts = Clock::get()?.unix_timestamp;
let (pda, _) = find_program_address(&[b"session", &ts.to_le_bytes()], program_id);
After (Fixed)
let (pda, _) = find_program_address(
&[b"session", user.key.as_ref()],
program_id,
);
Alternative Mitigations
1. Combine low-entropy with high-entropy seeds
When you need an index or counter, combine it with a high-entropy key:
let (pda, _) = find_program_address(
&[b"item", authority.as_ref(), &index.to_le_bytes()],
program_id,
);
2. Use multiple high-entropy sources
let (pda, _) = find_program_address(
&[b"escrow", user.as_ref(), counterparty.as_ref(), mint.as_ref()],
program_id,
);
3. Store timestamp separately from PDA derivation
If timestamp is needed for business logic, store it in account data rather than using it for PDA derivation:
let (pda, bump) = find_program_address(&[b"session", user.as_ref()], program_id);
// Store timestamp in account data, not in seeds
state.created_at = Clock::get()?.unix_timestamp;
Common Mistakes
Mistake 1: Using only an incrementing counter
// WRONG: fully enumerable (0, 1, 2, ...)
let (pda, _) = find_program_address(&[b"user", &user_id.to_le_bytes()], pid);
Combine with the authority’s public key to add entropy.
Mistake 2: Assuming slot numbers are high-entropy
// WRONG: slot numbers are sequential and predictable
let slot = Clock::get()?.slot;
let (pda, _) = find_program_address(&[b"tx", &slot.to_le_bytes()], pid);
Mistake 3: Using block hash as entropy
Block hashes are publicly observable and can be predicted within a window. They should not be relied upon as the sole entropy source for PDA seeds.