claim() function in staking.sol updates claimable[msg.sender] to 0 after transferring tokens to caller. Reentrancy is possible if the WETH is crafted to change the control flow such as erc777 which are backward compatible to erc20.
claim() function handovers control to msg.sender before updating claimable. msg.sender can reenter claim function until weth becomes 0.
Attack follows the following flow:
Staking contract has 10000 weth
Attacker calls deposits(10). (totalSupply set to 10)
This updates balance from 0 to 10000 and index 0 to 1000
1000 weth is deposited in 1 day.
Attacker calls claim(). The claimable[attacker] is calculated as 1000. (assuming totalSupply remains 10)
Attacker receives tokens and reenter contract until weth.balanceOf(staking) > 0.
As claimable[attacker] still gives 1000 or more. He can steal all weth in contract.
claimable[attacker] set to 0
balance is updated to 0
weth funds are stolen.
Foundry, Manual review
Update claimable[msg.sender] = 0 before transferring tokens.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.