The TokenManager::withdraw
function suffers from missing state update issues and doesn't update the user's balance after a successful withdrawal, leading to a state where users can withdraw the same amount multiple times.
Furthermore, the function may lacks access control, allowing any user to call it whereas the natspec specifies ** @dev Caller must be owner
. Although it wouldn't make sense to restrict the withdraw function to the Owner only, this leads to confusion.
Below is the TokenManager::withdraw
function:
User A has a balance of 100 USDC in the TokenManager.
User A calls withdraw to withdraw 100 USDC.
The function transfers 100 USDC to User A but doesn't update the balance.
User A can call withdraw again and receive another 100 USDC.
This process can be repeated until the contract is drained of USDC.
Paste the following test in PreMarkets.t.sol
:
This vulnerability could lead to significant fund loss. Attackers could potentially drain the contract of more funds than they should have access to.
Moreover, even non-malicious users could accidentally withdraw more funds than intended due to the lack of balance updates.
The lack of access control exacerbates these issues by allowing any user to exploit the vulnerabilities.
Manuel review - Testing
Implement the checks-effects-interactions pattern:
Update the user's balance before making any external calls.
Implement proper access control:
Add an onlyOwner
modifier if the function should only be callable by the owner.
Ensure all state changes are made before external calls.
transfer()
is not recommended anymore. Use call()
instead for sending Ether to prevent potential issues with gas limits.
Here's an example of how the withdraw function could be improved
These changes will ensure that the contract state remains consistent after withdrawals.
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.