The VaultDepositController:withdraw function is vulnerable to a reentrancy attack. The function performs external calls to transfer tokens before updating its internal state variables, which can be exploited by an attacker to repeatedly withdraw funds. This vulnerability is a common issue in smart contracts when they allow for reentrant function calls before properly updating their state.
The withdraw function is responsible for withdrawing tokens from vaults and transferring them to the caller. The core issue is that the function performs an external call to transfer tokens before updating critical state variables such as totalDeposits, totalPrincipalDeposits, and totalUnbonded.
Here's the relevant code snippet from the withdraw function:
The external call to token.safeTransfer() happens before the internal state variables (totalDeposits, totalPrincipalDeposits, and totalUnbonded) are updated. This means that an attacker could call back into the contract (re-enter) before the state is updated, potentially causing the contract to enter an inconsistent state or allowing for multiple withdrawals in a single transaction.
An attacker initiates a withdrawal request, triggering the withdraw function.
The function begins the withdrawal process and makes an external call to transfer tokens to the attacker's address.
Before the state variables are updated, the attacker can call back into the withdraw function, effectively restarting the withdrawal process.
Since the state hasn't been updated yet, the attacker can withdraw funds again, repeatedly draining the contract of its assets.
This vulnerability could result in a complete drain of the funds stored in the vaults if an attacker successfully executes a reentrancy attack. Besides allowing fund drainage, this vulnerability could cause a denial-of-service condition for legitimate users who are unable to withdraw funds due to depleted vaults. Repeated exploit attempts could cause the vault system to fail, preventing legitimate operations.
Manual Review
Rearrange the code to update the internal state variables before making any external calls, such as transferring tokens to the caller. This makes sure that even if a reentrant call occurs, the state has already been updated.
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.