Quick Answer
Solana's separation of program logic and account data is its most important architectural difference from EVM chains — and the source of its most common security failures. Every Solana program must validate every account it receives. The runtime enforces signatures; everything else is the program's responsibility.
Programs and data are separate. Programs receive accounts as instruction inputs and must validate owner, signer, discriminator, and content for each. Nothing is validated automatically except signatures.
Program Derived Addresses are deterministic from seeds. Poorly designed seeds allow an attacker to predict or collide PDA addresses, substituting one account for another in privileged instructions.
When a Solana program calls another via CPI, it can pass its authority accounts — but only those it legitimately has. CPI privilege escalation occurs when insufficient checks allow unintended account passing.
Account data is serialized with Borsh. Field order matters. Incorrect deserialization schema silently reads garbage bytes as valid field values — type system doesn't protect from schema mismatches.
| Vulnerability Type | Severity | Description | Example |
|---|---|---|---|
| Missing Account Owner Check | Critical | Solana programs receive accounts as instruction inputs. If a program doesn't verify that an account is owned by the expected program, an attacker can pass a malicious account with the correct shape but controlled data. Owner checks are not enforced by the runtime — the program must implement them. | A token program that checks account discriminator (shape) but not owner — an attacker creates a look-alike account owned by their own program, passes it to a privileged instruction, and executes operations on their crafted data. |
| Missing Signer Verification | Critical | Solana instructions can list multiple accounts, some of which must be signers. If a program doesn't verify that a required account actually signed the transaction, an attacker can pass any account in that position and execute privileged operations without authorization. | A governance instruction that accepts an 'authority' account but doesn't call require_signer(authority) — any account can be passed as the authority, bypassing the permission check. |
| PDA Seed Collision | High | Program Derived Addresses (PDAs) are deterministically derived from seeds and a program ID. If a program uses seeds that can be controlled or predicted by attackers, or if two different logical accounts can derive to the same PDA, an attacker can substitute one PDA for another in privileged instructions. | A protocol that derives a user's escrow PDA using only the user's pubkey as a seed — an attacker who controls a second account with the same pubkey (impossible, but the seed collision arises from incomplete seed design) or can predict another user's PDA can substitute accounts. |
| Borsh Deserialization Confusion | High | Solana uses Borsh (Binary Object Representation Serializer for Hashing) for account data serialization. Incorrect Borsh field ordering or type mismatches silently deserialize corrupted data without panicking — the program reads garbage bytes as valid field values. | A program that stores a u64 followed by a Pubkey in account data. An upgrade changes the order to Pubkey then u64 without migrating existing accounts — old data is deserialized with swapped field values, reading the high bytes of the old u64 as the first bytes of a pubkey. |
| Sysvar Account Substitution | Medium | Solana sysvars (Clock, Rent, SlotHashes, etc.) are special accounts providing runtime state. Programs that read sysvars without verifying the account is the canonical sysvar can be passed fake sysvar accounts with attacker-controlled values for timestamps, slot hashes, or rent. | A time-locked protocol that reads the current timestamp from an account passed as Clock sysvar but doesn't verify the account address — an attacker passes a crafted account with a far-future timestamp, unlocking funds before the lock period expires. |