Program Derived Addresses (PDAs) are a core Solana account model primitive that allows programs to deterministically derive addresses and sign for them without holding a private key. A PDA is a 32-byte address computed from a set of seeds and a program ID, deliberately placed off the ed25519 curve to ensure no external entity can generate a valid signature for it. This off-curve property is the security foundation: only the program that owns the PDA can "sign" via invoke_signed, making PDAs the canonical mechanism for programmatic custody of token accounts, state accounts, and authority records across the Solana ecosystem.

Program Derived Address (PDA) Design Patterns
Introduction
Program Derived Addresses are the foundational primitive for programmatic custody on Solana, enabling deterministic account derivation and off-curve signing authority.
The canonical PDA derivation process uses Pubkey::find_program_address, which iterates through bump seeds (starting at 255 and decrementing) until it finds an address off the ed25519 curve. The resulting bump seed becomes part of the derivation path and must be stored or re-derived for every invoke_signed call. Misunderstanding this bump seed lifecycle is the root cause of many security vulnerabilities: programs that accept user-supplied bump seeds without validation, programs that fail to verify PDA ownership before modifying account data, and programs that conflate PDA derivation with authority checks all create privilege escalation vectors that auditors systematically target during security reviews.
PDA design patterns extend beyond simple derivation into multi-signer CPI contexts, where a single instruction can authorize actions across multiple PDAs simultaneously. This enables complex atomic operations—like moving funds between two program-controlled vaults or updating interdependent state accounts—without requiring intermediate transactions. However, these patterns introduce subtle security considerations around seed collision, bump seed canonicalization, and the distinction between PDA signer privileges and account ownership. Teams building upgradeable programs face additional complexity: if a program's upgrade authority changes the program ID, all existing PDAs become orphaned unless migration logic is embedded in the original derivation design.
For protocol architects and security reviewers, PDA design patterns represent a critical intersection of account model constraints, runtime behavior, and authorization logic. Chainscore Labs provides PDA-focused security reviews that examine bump seed handling, seed collision resistance, CPI authorization chains, and upgrade-related PDA migration risks. Teams deploying programs that rely on complex PDA hierarchies or multi-signer CPI flows should engage a review before mainnet deployment to identify privilege escalation paths that static analysis tools frequently miss.
Quick Facts
Operational and security facts about Program Derived Addresses that affect program design, audit surface, and account authority management
| Field | Value | Why it matters |
|---|---|---|
Deterministic derivation | PDAs are derived from a program ID and a set of seeds, optionally including a bump seed to push the address off the ed25519 curve | Programs can deterministically locate and control accounts without managing a private key, enabling state management and cross-program interaction patterns |
Bump seed canonical range | Bump seeds are a single byte (u8) in the range 0–255, with 255 being the starting point for find_program_address iteration | Using a non-canonical bump (one that is not the highest valid bump) can break composability and cause security issues if other programs derive the PDA with the canonical bump |
Signer authority | PDAs can act as signers in CPIs via invoke_signed, but they cannot sign transactions directly because they lack a private key | This allows programs to control token accounts, escrow vaults, and governance authorities without exposing a private key, but requires careful seed management to prevent unauthorized signing |
Seed collision risk | If a program uses user-supplied seeds without domain separation or type prefixes, different logical accounts can map to the same PDA | Seed collision is a common privilege escalation vector where an attacker can reuse a PDA intended for one purpose to authorize an unrelated action |
Close-and-reinitialize attack | If a program closes a PDA account and later re-derives it with the same seeds, an attacker can reinitialize the account with malicious state before the program uses it again | Auditors flag this as a critical vulnerability; mitigation requires either never reusing a closed PDA's seeds or checking the account's owner and data length after re-derivation |
Multi-signer PDA derivation | A single instruction can use invoke_signed with multiple PDAs, each derived from different seeds, to satisfy multi-signer requirements in a CPI | This enables complex custody patterns like multi-party escrow or DAO-controlled treasuries, but requires the program to correctly derive and pass all required signer seeds |
PDA as token account authority | Token-2022 and SPL Token accounts can have a PDA as their authority, enabling programmatic control over token transfers, freezes, and closes | This is the foundation for escrow programs, AMM pools, and staking derivatives, but incorrect authority validation can lead to total loss of funds |
Technical Mechanism
How PDAs create program-controlled addresses without private keys, and why the bump seed is the critical security primitive.
Program Derived Addresses (PDAs) are Solana's mechanism for creating accounts that are owned and controlled by on-chain programs rather than by external keypairs. A PDA is derived deterministically by hashing a set of seeds—typically including a user's wallet address, a static string, and other contextual data—along with the program's own ID. The resulting 32-byte output is checked to ensure it falls off the ed25519 curve, guaranteeing that no corresponding private key exists. This cryptographic property is the foundation of PDA security: because no external signer can produce a valid signature for the address, only the owning program can authorize state changes to the account via invoke_signed.
The invoke_signed function is the sole mechanism by which a program can 'sign' for a PDA during a Cross-Program Invocation (CPI). The program provides the same seeds used to derive the PDA, along with a bump seed—a single byte that pushed the address off the ed25519 curve during derivation. The runtime re-derives the address from the provided seeds and program ID, and if it matches the PDA in the instruction's account list, the runtime treats the program as a valid signer. The canonical bump is the first bump value (starting from 255 and decrementing) that produces an off-curve address. Using a non-canonical bump is functionally valid but wastes compute units and is a strong indicator of a flawed or malicious program, as it can be used to create multiple valid derivation paths for the same logical account.
The most critical security anti-pattern in PDA design is the failure to validate all seeds, particularly user-provided ones. If a program derives a PDA using a user's wallet address as a seed but does not verify that the user has signed the transaction, an attacker can substitute their own address, derive a different PDA, and hijack the account's authority. This class of 'type substitution' or 'seed injection' vulnerability is a leading cause of privilege escalation bugs. Auditors systematically check that every PDA derivation in a program is accompanied by a corresponding signer check or an equivalent constraint that anchors the PDA to a specific, transaction-signed authority. The Anchor framework's seeds constraint in its #[account(...)] macro automates this check, but native programs must enforce it manually in their instruction handlers.
Affected Actors
Program Developers
PDA design flaws are the most common source of critical vulnerabilities in Solana programs. Developers must ensure that every PDA derivation includes a unique seed domain separator to prevent cross-function collision attacks.
Immediate actions:
- Audit all
Pubkey::find_program_addresscalls for missing or weak seeds. - Verify that bump seeds are stored on-chain and validated on every instruction invocation.
- Ensure that programs check both the account owner and the PDA derivation before trusting account data.
Chainscore Labs can review your program's PDA architecture, identify missing authorization checks, and harden your derivation logic against privilege escalation attacks.
Core Design Patterns
Canonical patterns for deterministic, program-controlled accounts and the critical security rules that prevent privilege escalation.
Deterministic Address Derivation
PDAs are derived using a program ID and a set of seeds via find_program_address. This creates an address off the ed25519 curve, ensuring no private key exists. The canonical bump seed (the first valid bump found, starting from 255) must be stored and validated on every instruction to prevent bump seed canonicalization attacks where an attacker provides a different bump to create a distinct PDA.
Signer Authorization via `invoke_signed`
Programs authorize PDA actions using invoke_signed, which generates a synthetic signature from the program's ID and the exact seeds and bump used to derive the PDA. A mismatch in seeds or bump will cause the CPI to fail. This pattern is essential for token vaults, escrow accounts, and cross-program interactions where the PDA must act as a signer without a private key.
Multi-Signer PDA Derivation
For shared control, PDAs can be derived using multiple public keys as seeds. A common pattern for a 2-of-2 escrow between users A and B is find_program_address(&[b"escrow", user_a.key.as_ref(), user_b.key.as_ref()], program_id). This ensures the escrow account is deterministically tied to both parties and can only be controlled by the program when both users authorize the interaction.
Anti-Pattern: Missing Bump Validation
A critical vulnerability flagged by auditors is failing to validate the bump seed provided by the caller. If a program uses create_program_address with a user-supplied bump instead of re-deriving and checking it, an attacker can forge a valid PDA for a different set of seeds. Always re-derive the PDA using find_program_address and assert the bump matches the one stored in the account or provided by the caller.
Anti-Pattern: Authority Mix-Up in CPI
A privilege escalation bug occurs when a program uses its own PDA as the signer for a CPI but fails to verify the authority of the accounts it is modifying. For example, a program might use its PDA to close a token account without checking that the token account's owner is the PDA. An attacker could pass a victim's token account and drain it. Always verify that the target account's owner field matches the expected PDA before signing.
Pattern: PDA as a Token Vault
A foundational DeFi pattern is a PDA-owned token account. The program derives a PDA using seeds like b"vault" and the user's public key, then creates an associated token account (ATA) with that PDA as the owner. Funds can only be moved by the program via invoke_signed with the correct seeds. This pattern underpins escrow, staking, and liquidity pool contracts by guaranteeing that only the program logic can release user deposits.
Security Anti-Patterns and Risks
Recurring security flaws in PDA-based authorization that lead to privilege escalation, unauthorized fund transfers, or account takeover. Each row identifies a failure mode, how it manifests in Solana programs, which actors are exposed, and the recommended verification or remediation step.
| Anti-Pattern | Failure mode | Who is affected | Mitigation |
|---|---|---|---|
Missing bump seed validation | Program accepts a user-supplied bump without verifying it produces the expected PDA, allowing an attacker to forge a PDA from a different canonical bump | DeFi protocols, token vaults, staking programs | Always derive the PDA on-chain using Pubkey::find_program_address and validate the provided bump matches |
Unchecked account owner in PDA authorization | Program assumes a PDA is owned by itself without verifying the owner field, allowing an attacker to pass an account owned by a malicious program that mimics the PDA address | Lending protocols, escrow programs, AMM pools | Explicitly check that ctx.accounts.pda.owner == program_id before trusting the account data |
Type confusion via PDA reuse | Same PDA seed derivation is used for multiple account types, allowing an attacker to pass a valid PDA of one type where another type is expected | Protocols with multiple PDA-governed vaults or state accounts | Include a unique discriminator in seeds (e.g., b"vault" vs b"state") and validate account discriminator bytes on deserialization |
Missing signer seed invocation | Program derives a PDA but fails to invoke it with the seeds during CPI, causing the CPI to lack the PDA's signing authority | Programs managing token accounts or executing cross-program transfers | Use invoke_signed with the correct seeds and bump when the PDA must act as a signer in CPIs |
Arbitrary CPI destination with PDA authority | Program invokes an arbitrary program provided by the user using the PDA's signer privileges, enabling privilege escalation through a malicious CPI target | Programs that delegate PDA signing to user-specified programs | Whitelist allowed CPI destinations or restrict the program ID to known, verified programs |
PDA initialization without rent-exemption check | Program initializes a PDA account without verifying it is rent-exempt, allowing an attacker to drain lamports or cause account closure | Programs that dynamically create PDA accounts | Verify account.lamports() >= Rent::get()?.minimum_balance(space) before marking the account as initialized |
Reinitialization attack on PDA | Program fails to check that a PDA has not already been initialized, allowing an attacker to reinitialize it with attacker-controlled data or overwrite critical state | Programs with one-time PDA initialization flows | Check for a discriminator or initialized flag at the start of the instruction and reject if already set |
Seed collision across users or scopes | PDA seeds lack user-specific or scope-specific components, allowing one user's PDA to collide with another's or enabling cross-account manipulation | Multi-user protocols, DAOs, token vesting contracts | Include the user's public key, a unique identifier, or a domain separator in the seed derivation to ensure isolation |
Developer Implementation Checklist
A practical checklist for developers implementing Program Derived Addresses. Each item targets a common vulnerability or integration failure that auditors and runtime experts flag during security reviews.
What to check: Every instruction that receives a PDA account must re-derive the address on-chain using Pubkey::find_program_address and compare it against the provided account key.
Why it matters: The runtime does not automatically verify that a provided account is the correct PDA for the given seeds. Without explicit validation, an attacker can supply a different account controlled by them, leading to unauthorized access to privileged program state.
Readiness signal: Your instruction handler contains an explicit assert_eq!(derived_key, ctx.accounts.my_pda.key()) check before any mutable access to the account data.
Source Resources
Canonical resources for implementing, reviewing, and testing Program Derived Address patterns on Solana. Use these sources to verify derivation rules, signer semantics, Anchor constraints, and local test coverage before deploying PDA-controlled state.
Looking to build on a specific blockchain?
We build smart contracts, DeFi applications, wallets, tokenization platforms, and blockchain infrastructure across the major ecosystems teams choose today. That includes Ethereum, Arbitrum, Optimism, Polygon, Avalanche, Solana, Sui, Aptos, Hedera, Stellar, and NEAR, with support for additional EVM and non-EVM networks based on your product requirements.
EVM ecosystems
- Ethereum
- Arbitrum
- Optimism
- Polygon
- Avalanche
- Cronos

Non-EVM ecosystems
- Solana
- Sui
- Aptos
- Hedera
- Stellar
- NEAR
Additional ecosystems
- Polkadot
- Cosmos
- TON
- Cardano
- Algorand
- Tempo
Also available for Base, appchains, custom EVM networks, and cross-chain product architecture.
Frequently Asked Questions
Common questions from developers and auditors about Program Derived Address design patterns, bump seed management, and privilege escalation risks.
Missing or improper signer seed validation. The most frequent critical finding is a program that derives a PDA but fails to verify that the correct signer seeds were used, allowing an attacker to provide a different set of seeds that derives the same PDA but grants unauthorized access.
What to check:
- Every PDA used as a signer must have its seeds validated against expected values, not just its address
- Seeds provided by users (e.g., user pubkeys, token mint addresses) must be verified to match the expected authorization context
- The bump seed must be canonical—using a user-supplied bump without validation is a common vector
Why it matters: An attacker can craft alternative seed combinations that derive the same PDA but represent a different authorization context, effectively bypassing access controls.
Delivering blockchain solutions for 5+ years.
We have partnered with 50+ leading DeFi protocols, NFT ecosystems, and fintech innovators to build secure, scalable, and capital-efficient blockchain products.
Selected Partners & Clients
“I've been working with Chainscore Labs for last 3+ years, they've consistently delivered with strong ownership across multiple projects. The team is reliable and detail-oriented.”
How to get started?
If you're looking for blockchain integration, ChainScore Labs has 5+ years of experience helping teams build and integrate exchanges, wallets, smart contracts, tokenization solutions, and protocol-connected products, we can help you choose the right path, integrate securely, and get to production faster. Our team consists of experienced blockchain developers and architects who can help you with your blockchain integration needs.
Exploration & Strategy
Define your product goals and choose the right blockchain architecture for your use case.
Architecture & Design
Design the smart contracts, tokenomics, and security parameters of your system.
Development & Integration
Build and integrate with wallets, oracles, and front-end dApps for a seamless experience.
Security & Launch
Comprehensive audits followed by a risk-managed mainnet deployment to protect your users.
Discover our
blockchain development services.
We build production-grade blockchain solutions for top-tier projects across DeFi and Web3.
Need a blockchain engineering team?
Send the project context and we will respond with next steps, scope questions, and a practical path to delivery.


