The important thing here is the difference between create_program_address
and find_program_address
. The difference between these two is find_program_address
takes in only the seeds and searches for the first bump itself, while create_program_address
takes in the seeds and bump. If you use find_program_address
for both creating and validating PDAs, you're fine.
However, this attack is possible if you use create_program_address
and aren't careful (the reason you might use this one is because it's cheaper in CUs than find_program_address
is).
If you use it for creation and allow the user to specify the bump (you might do this to save CUs), they can obviously create multiple PDAs by specifying different bumps with the same seeds. If you use find_program_address
for creation and create_program_address
for checking if a PDA exists already, users might not be able to trick your program into creating multiple PDAs like before, but they can trick it into believing an account doesn't exist yet.
Both of these are dangerous because it allows an attacker to fake the existence and/or the content of data to a program.
Existence:
Let's say you have some action that should only be allowed once (e.g. claiming an airdrop). A simple way to implement this functionality would be to say once a user has performed this action, you create a PDA using the user's public key as the seeds (and you then check for the existence of said PDA to verify if the user has already performed the action). If you accept non-canonical bumps, a malicious user could potentially perform your one-time action up to 256 times (since each PDA has 256 possible bump values).
Content: Let's say your program stores some information about each account that interacts with it. You do this by creating a PDA for each user using the user account as seeds and storing your data in the PDA. A malicious user could create up to 256 PDAs for himself and supply only whichever of these contains data that is most beneficial to them in that moment.
Obviously these are quite simple example, but since PDAs are used for heaps of things, attacks where you can fake the existence/contents of PDAs can cause heaps of problems, so it's best to always validate bumps by default unless you're sure you don't need to.