Full Report
Solana is a blockchain that allows for the execution of arbitrary Rust code. The main difference is that information is stored in accounts - both code and data. Program Derived Addresses (PDAs) are public keys that are derived from the address of the program itself. By using a specific seed, the address can be bumped off of the elliptic curve to ensure there is no valid key for it. To generate the PDA, the following valued are used then hashed: hash(seed + program_id + "ProgramDerivedAddress"). When using PDAs, it is cumbersome because a private key must be created for the account and sign the transaction with it. As an alternative, create_with_seed was made. This is a feature of the system program. So, it can create an account and assign ownership to the account. The address of this is calculated by hash(base + seed + owner). These two methods are pretty similar in how they generate code, right? Since there are no separators or unique prefixes for this in Solana, there is the potential for a hash collision! There some constraints though, such as account being system owned and the first 21 bytes of the program_id being valid UTF-8 (1 out of 180K). How would this been useful? A collision like this could have allowed for an awesome rug pull mechanism. There is no way an audit would have caught this either. This was fixed by ensuring that the owner of a seeded account cannot end with ProgramDerivedAddress.
Analysis Summary
# Vulnerability: Solana PDA and Seeded Account Hash Collision
## CVE Details
- **CVE ID**: Not explicitly assigned (Referenced as Neodyme-Solana-Core-01)
- **CVSS Score**: Estimated 7.5 (High)
- **CWE**: CWE-335 (Incorrect Usage of Seed in Pseudo-Random Number Generator) / CWE-911 (Improper Update of Reference Count)
## Affected Systems
- **Products**: Solana Core (Mainnet-Beta, Testnet, Devnet)
- **Versions**: Versions prior to the June 2021 security patch (specifically before commit `0ed9f714`).
- **Configurations**: Programs using Program Derived Addresses (PDAs) where the `program_id` meets specific UTF-8 byte constraints.
## Vulnerability Description
The vulnerability stems from a logical overlap in how the Solana runtime calculates two different types of account addresses: **Program Derived Addresses (PDAs)** and **Seeded Accounts**.
1. **PDA Calculation**: `hash(seeds + program_id + "ProgramDerivedAddress")`
2. **Seeded Account Calculation**: `hash(base_pubkey + seed + owner)`
Because Solana did not use unique prefixes or separators between these concatenated inputs, a hash collision could be engineered. If an attacker could make the `owner` field of a Seeded Account end with the static string `"ProgramDerivedAddress"`, and the preceding bytes of that `owner` matched a target `program_id`, the resulting address would be identical to a PDA.
By exploiting this, an attacker could pre-create a "Seeded Account" (which they control) at the exact address where a smart contract would later attempt to derive a "PDA" (vault).
## Exploitation
- **Status**: PoC available (developed by Neodyme); no known exploitation in the wild.
- **Complexity**: High. Requires "grinding" a `program_id` where the first 21 bytes are valid UTF-8 and the suffix aligns with the PDA marker. The article estimates a 1 in 180,000 chance for a valid ID.
- **Attack Vector**: Network. An attacker deploys a specific program ID and uses the System Program to claim addresses before they are initialized by the victim's contract.
## Impact
- **Confidentiality**: None.
- **Integrity**: High. Allows an attacker to intercept funds intended for a program vault or take ownership of accounts the program believes it uniquely controls.
- **Availability**: High. Can be used for Denial of Service (DoS) by squatting on PDA addresses, preventing legitimate contracts from initializing their state.
## Remediation
### Patches
- The vulnerability was fixed in the Solana core repository via commit `0ed9f7144cd1749d4060c0652bca04beeabc7dea` on June 18, 2021.
- Updated Solana releases ensure that the `owner` of a seeded account cannot end with the `ProgramDerivedAddress` constant.
### Workarounds
- **For Developers**: Before the patch, developers were advised to check if an account was already initialized or owned by an unexpected program before transacting.
## Detection
- **Indicators of Compromise**: Accounts used as program vaults that are owned by the System Program instead of the expected Program ID.
- **Tools**: Solana CLI or block explorers can be used to inspect account ownership. Any PDA address that was created via `create_with_seed` rather than `create_program_address` is a high-risk indicator for this specific flaw.
## References
- Neodyme Advisory: hxxps://neodyme[.]io/en/blog/solana_core_1
- Solana Security Policy: hxxps://github[.]com/solana-labs/solana/blob/master/SECURITY.md
- Fix Commit: hxxps://github[.]com/solana-labs/solana/commit/0ed9f7144cd1749d4060c0652bca04beeabc7dea