🔴 H01 - Attacker can copy valid message and call solana-vault::oapp_lz_receive
with arbitrary ctx.accounts allowing him to steal tokens from vault_deposit_wallet
An attacker can to listen for message sent on source chain, and execute them with crafted inputs on the destination chain to drain the protocol owned token account.
The solana-vault::oapp_lz_receive
instruction can be called by anyone, as no verification is done on the transaction signer. Also, no checks are performed regarding the content of the message, and the actual token accounts provided with the instructions and involved in the token transfers.
The transfer is done from the vault_deposit_wallet
(owned by PDA owned by the solana-vault program) to the user_deposit_wallet
(which isn't verified), this allows an attacker to unauthorizedly drain USDC tokens from the vault_deposit_wallet
This allows an attacker to listen for message sent from the source chain, and front-run on the destination chain the Executor call to solana-vault::oapp_lz_receive
, by replicating the content of the sent message, but maliciously swapped the user_deposit_wallet
account provided in the instruction context, which don't match the expected receiver of the message.
Also, it seems that in the current implementation of the Uln program, the attacker can proceed with the verification himself as there is no restriction on the caller, but here we don't even need that hypothesis as our attacker can simply wait for the verification to be commited to then call the solana-vault::oapp_lz_receive
function.
See how, in contrast, another project checks the receiving wallet against the message param
solana-vault::oapp_lz_receive
can be called by anyone- no check ensuring that the transfer correspond to the received message
- transfer is executed using a PDA signer owned by the calling contract, meaning anyone can execute the transfer if no specific verification checks are done.
- Victim request a withdrawal from source chain
- Message get sucessfully verified on destination chain
- Attacker detect victim withdrawal request and extract the message
- Attacker calls
solana-vault::oapp_lz_receive
before the Executor with malicious inputs
- Alice request a withdrawal
- The message is constructed on the EVM Oapp (source chain) and sent through LZ to the Solana Oapp (destination chain)
- at this point, the attacker sees the transaction on the source chain and extract the message
- The message get verified
- this update the
payload_hash.hash
which is necessary when clear is called (1)(2) during thesolana-vault::oapp_lz_receive
instruction
- this update the
- Once the message gets verified the attacker call
solana-vault::oapp_lz_receive
with the extracted message but provide its ownuser_deposit_wallet
account rather than Alice's one - the transfer is executed and the attacker receive the funds
Loss of funds This also break the following README property
Ensure that user_deposit_wallet
is the one expected in the message payload.