Skip to content

Commit 8864416

Browse files
authored
Add PDA example contract (NSSC Solana)
1 parent 6981b21 commit 8864416

File tree

1 file changed

+19
-3
lines changed
  • not-so-smart-contracts/solana/improper_pda_validation

1 file changed

+19
-3
lines changed
Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,34 @@
11

2-
# [WIP] Improper PDA bump seed validation
2+
# Improper PDA bump seed validation
33

44
PDAs (Program Derived Addresses) are, by definition, [program-controlled](https://docs.solana.com/terminology#program-derived-account-pda) accounts and therefore can be used to sign without the need to provide a private key. PDAs are generated through a set of seeds and a program id, which are then collectively hashed to verify that the key doesn't lie on the ed25519 curve (curve used by Solana to sign transactions).
55

6-
Values on this elliptic curve have a corresponding private key, which wouldn't make it a PDA.
7-
In the case a public key lying on the elliptic curve is found, our 32-byte address is modified through the addition of a bump to "bump" it off the curve. A bump, represented by a singular byte iterating through 255 to 0 is added onto our input until an address that doesn’t lie on the elliptic curve is generated, meaning that we’ve found an address without an associated private key.
6+
Values on this elliptic curve have a corresponding private key, which wouldn't make it a PDA. In the case a public key lying on the elliptic curve is found, our 32-byte address is modified through the addition of a bump to "bump" it off the curve. A bump, represented by a singular byte iterating through 255 to 0 is added onto our input until an address that doesn’t lie on the elliptic curve is generated, meaning that we’ve found an address without an associated private key.
87

98
The issue arises with seeds being able to have multiple bumps, thus allowing varying PDAs that are valid from the same seed. An attacker can create a PDA with fabricated data - the program ID and seeds are the same as the expected PDA but with different bump seeds. Without any explicit check against the bump seed itself, the program leaves itself vulnerable to the attacker tricking the program into thinking they’re the expected PDA and thus interacting with the contract on behalf of them.
109

1110
View ToB's lint implementation for the bump seed canonicalization issue [here](https://github.com/crytic/solana-lints/tree/master/lints/bump_seed_canonicalization).
1211

1312
## Exploit Scenario
1413

14+
In Solana, the `create_program_address` function creates a 32-byte address based off the set of seeds and program address. On it's own, the address may lie on the ed25519 curve. Consider the following without any other validation being referenced within a sensitive function, such as one that handles transfers. That PDA could be spoofed by a passed in user-controlled PDA with malicious functions to their own discretion.
1515
### Example Contract
16+
```rust
17+
let program_address = Pubkey::create_program_address(&[key.to_le_bytes().as_ref(), &[reserve_bump]], program_id)?;
1618

19+
...
20+
```
1721
## Mitigation
1822

23+
The `find_program_address` function continously checks the expected value (via passing in the intended bump seed) and will return an error in the case the PDA address and/or bump don't match with the expected values.
24+
25+
```rust
26+
let (address, system_bump) = Pubkey::find_program_address(&[key.to_le_bytes().as_ref()], program_id);
27+
28+
if program_address != &account_data.key() {
29+
return Err(ProgramError::InvalidAddress);
30+
}
31+
if system_bump != reserve_bump {
32+
return Err(ProgramError::InvalidBump);
33+
}
34+
```

0 commit comments

Comments
 (0)