Missing PDA validation leading to multiple transfers
Description
Rewards are redeemed using a two-step process. First, signed messages are submitted and stored on-chain in an account of type VerifiedMessages
. When the required amount of signed messages has been submitted, the EvaluateAttestations
instruction is invoked to process the transfer. The instruction performs a number of checks on the provided accounts and then performs the token transfer to the destination account. In order to avoid a single transfer being repeated multiple times, a PDA is created (transfer_account_info
), marking the transfer as completed. The PDA is unique for the transfer since the address is derived from the details of the transfer, including a unique ID. In addition, the account containing the VerifiedMessages
is deleted by zeroing its lamports. Both these measures are flawed and can be bypassed.
The transfer_account_info
account is not checked to be the intended PDA. An attacker can supply any signer account as an input to the transaction, and the account will be created successfully. This is because any signer account can be passed to the create_account
system instruction, even if the invoke_signed
function is used to perform an invocation with signer seeds for the intended PDA. The signer seeds will just be ignored as they do not correspond to any account in the subtransaction.
It is also possible to reuse the VerifiedMessages
account, despite it having zero lamports, by referencing it in multiple instructions within the same transaction. This specific issue is discussed more in detail in the unsafe account deletion finding.
Impact
It is possible to redeem rewards multiple times. We confirmed this issue by modifying an existing test.
Recommendations
Ensure that the transfer_account_info
account matches the expected PDA. Properly invalidate the data stored in the VerifiedMessages
accounts so that it cannot be reused even within the same transaction.
Remediation
The Audius team was alerted of this issue while the audit was ongoing. The issue was acknowledged within 10 minutes, and a remediation patch was suggested within 40 minutes. The patch was quickly deployed after review from both Zellic and Audius engineers to ensure a complete fix to the issue. The complete timeline of events follows (times in UTC, October 15th):
17:52 Audius is informed of the issue
18:02 Audius acknowledges the issue
18:31 Audius proposes a remediation
18:35 Zellic confirms that proposed remediation patches the issue, suggesting additional changes to invalidate
VerifiedMessages
accounts~21:45 Audius finalizes remediation commits, including suggested additional changes
~22:00 Zellic confirms that remediation patches the issue
~22:00 Audius deploys and tests patch on testnet
23:31 Audius deploys patch on mainnet