Stakers can exploit this timing gap to withdraw their staked tokens without incurring the losses that would normally result from penalties or slashing events.
Proof of Concept
A validator experiences penalties or is slashed, reducing their balance.
The staker then triggers the update of the TVL by calling one of the aforementioned functions.
When withdraw is executed, the withdrawal is processed without accounting for the recent penalties or slashing, as the TVL drop is instantaneous upon the update.
for example:
Initial state:
2 validators 32 ETH each
10 users with equal LRT, 6.4 each.
Validator 1 is slashed for 16 ETH
User 1 front-runs verifyBalanceUpdates() with a call to tWithdrawal() and has sharesOwed = 6.4 since TVL is still 64 ETH.
verifyBalanceUpdates() is now called to update EigenLayer balance.
User 2 calls withdraw() and has sharesOwed = 4.8 since TVL has decreased to 48.
User 1 has stolen 1.4 ETH from the rest.
Tools Used
Manual Review
Recommended Mitigation Steps
Locking Period: Implement a locking period after a slashing event is detected, during which no withdrawals can be processed. This allows the system to update the TVL accordingly.
Lines of code
https://github.com/code-423n4/2024-04-renzo/blob/1c7cc4e632564349b204b4b5e5f494c9b0bc631d/contracts/Withdraw/WithdrawQueue.sol#L206 https://github.com/code-423n4/2024-04-renzo/blob/1c7cc4e632564349b204b4b5e5f494c9b0bc631d/contracts/Withdraw/WithdrawQueue.sol#L279
Vulnerability details
Impact
Stakers can exploit this timing gap to withdraw their staked tokens without incurring the losses that would normally result from penalties or slashing events.
Proof of Concept
A validator experiences penalties or is slashed, reducing their balance.
Before the TVL is updated via EigenPod::verifyBalanceUpdates() or EigenPod::verifyAndProcessWithdrawals(), a staker requests a withdraw all their
LRTTokens
using withdraw.The staker then triggers the update of the TVL by calling one of the aforementioned functions. When withdraw is executed, the withdrawal is processed without accounting for the recent penalties or slashing, as the TVL drop is instantaneous upon the update.
for example:
Initial state: 2 validators 32 ETH each 10 users with equal LRT, 6.4 each.
verifyBalanceUpdates()
with a call to tWithdrawal() and has sharesOwed = 6.4 since TVL is still 64 ETH.verifyBalanceUpdates()
is now called to update EigenLayer balance.withdraw()
and has sharesOwed = 4.8 since TVL has decreased to 48.User 1 has stolen 1.4 ETH from the rest.
Tools Used
Manual Review
Recommended Mitigation Steps
Locking Period: Implement a locking period after a slashing event is detected, during which no withdrawals can be processed. This allows the system to update the TVL accordingly.
Assessed type
Context