Because the withdraw function does not reset the corresponding userTokenBalanceMap[_msgSender()][_tokenAddress][_tokenBalanceType] to 0, msg.sender is able to repeatedly call it to claim the same claimAbleAmount each time. This allows such msg.sender to steal multiples of such claimAbleAmount, other than his first claim of such claimAbleAmount, that do not belong to him from the capital pool.
Calling the following withdraw function executes uint256 claimAbleAmount = userTokenBalanceMap[_msgSender()][_tokenAddress][_tokenBalanceType] in which such claimAbleAmount is then claimed by msg.sender through either the payable(msg.sender).transfer or _safe_transfer_from function call. However, since such userTokenBalanceMap[_msgSender()][_tokenAddress][_tokenBalanceType] is not reset to 0, such msg.sender can repeatedly call the withdraw function to claim the same claimAbleAmount each time until the capital pool's token balance of the _tokenAddress is depleted.
After the corresponding msg.sender repeatedly calls the withdraw function to claim the same claimAbleAmount each time, he has stolen multiples of such claimAbleAmount, other than his first claim of such claimAbleAmount, that do not belong to him from the capital pool.
Manual Review
The withdraw function can be updated to reset the corresponding userTokenBalanceMap[_msgSender()][_tokenAddress][_tokenBalanceType] to 0 before transferring the corresponding claimAbleAmount to msg.sender.
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.