The withdraw()
function in the TokenManager
contract is vulnerable to reentrancy attacks. The function updates the user’s balance after transferring tokens, allowing an attacker to potentially drain more funds than they should be entitled to.
In the provided withdraw()
function, the token transfer is executed before the user’s balance is updated:
The vulnerability lies in the fact that the userTokenBalanceMap
is not updated before the token transfer occurs. This allows an attacker to potentially call the withdraw()
function multiple times before their balance is set to zero
An attacker could potentially drain more tokens than they are entitled to, leading to significant financial losses for the protocol and its users
maual code review
To mitigate this vulnerability, follow the Checks-Effects-Interactions (CEI) pattern. Update the user’s balance before making any external calls. This change ensures that the user’s balance is set to zero before any tokens are transferred, preventing reentrancy attacks.
Also consider adding a reentrancy guard. While the function already has a whenNotPaused
modifier, an additional reentrancy guard can provide an extra layer of security.
We can revise the withdraw()
function like so:
Valid critical severity finding, the lack of clearance of the `userTokenBalanceMap` mapping allows complete draining of the CapitalPool contract. Note: This would require the approval issues highlighted in other issues to be fixed first (i.e. wrong approval address within `_transfer` and lack of approvals within `_safe_transfer_from` during ERC20 withdrawals)
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.