Closed howlbot-integration[bot] closed 1 month ago
alex-ppg marked the issue as unsatisfactory: Out of scope
Hi @alex-ppg
Thank you for your time and effort in judging this contest. I appreciate you. Respectfully, I would like to shed more light on why this issue should not be considered OOS and why it should be considered valid.
First of all, I want to point out that it was explicitly stated in the README that we could assume that more tokens could be added in future:
Question | Answer |
---|---|
ERC20 used by the protocol | USDB, WETH, (assume we can add more to the future for use in LockManager) |
Also, the README stated that:
Question | Answer |
---|---|
Doesn't revert on failure | Yes |
Also, I would like to mention that, although this issue was reported in the 4naly3er as MEDIUM but the impact described in the 4naly3er was vague and is more severe than indicated.
And according to C4 docs,
Wardens may use automated tools as a first pass, and build on these findings to identify High and Medium severity issues ("HM issues").
Given these facts, the report which was submitted highlighted how severe the impact of this issue could be as regards to the fact that we can make assumptions that in future, ZRX
can be used in LockManager
as a principal token and ZRX
is a token that does not revert on failure, instead it simply returns a bool value that is not checked. The same behavior applies to the BNB
token.
This issue could lead to a loss of user funds. If the contract lacks sufficient tokens and the transfer fails, the transaction will still be marked as successful. Consequently, the player will receive zero tokens, and their claim will be voided as lockedToken.quantity
would be set. These lost tokens would be irretrievable.
Also it is also very risky for the LockManager contract because the contract can also lose assets.
Let's assume a scenario that the BNB
token, which Bob locks, does not revert on failure but instead returns a boolean value indicating success or failure.
The _lock()
function does not verify the returned boolean value. If the token transfer from Bob to LockManager.sol
fails. Despite this failure, the _lock()
function would remain unaware and will proceed to update the lockedTokens[Bob][_tokenContract]
data for Bob as if the transfer had succeeded.
This flaw allows Bob to reap the benefits of token locking without actually locking any tokens.
Furthermore, if Bob calls the unlock()
function with a positive _quantity
, LockManager.sol
would end up losing tokens to Bob.
I firmly believe this issue should be deemed valid, as addressing it now could be highly beneficial for the protocol, especially if additional ERC20 tokens are integrated in the future.
However, I defer to your judgment and will respect any decision you make on this matter.
Hey @Rhaydden, thanks for your contributions. I am fully aware of the C4 guideline in relation to static-analyzer reported issues, however, I cannot consider an upgrade of one tier (i.e. an M
to an H
) being a valid submission under this guideline given that H and M risk issues are of equivalent importance in the Sponsor remediating them. Mislabelling a finding as M
when it is H
is of no actual impact on the Sponsor's remediation actions (i.e. the reason that static analyzer submissions are out-of-scope), and thus my original ruling remains for this finding.
Lines of code
https://github.com/code-423n4/2024-05-munchables/blob/57dff486c3cd905f21b330c2157fe23da2a4807d/src/managers/LockManager.sol#L419-L423 https://github.com/code-423n4/2024-05-munchables/blob/57dff486c3cd905f21b330c2157fe23da2a4807d/src/managers/LockManager.sol#L376
Vulnerability details
Impact
Impact is HIGH. This issue could potentially lead to loss of funds and can make a user unable to unlock their locked tokens.
Proof of Concept
For the scope of this audit, the README states that we can assume more tokens can be added for use in
LockManager
in future.Also according to the README,
In the
LockManager.sol
contract, thetransferFrom
and transfer function is used without checking its return value:Now,
ZRX
is a token that fits these conditions and can theoretically be used inLockManager
as a principal token. https://coinmarketcap.com/dexscan/ethereum/0xfa97aa5002124fe7edd36584628300e8d81df042/ZRX is a token that does not revert on failure, instead it simply returns a bool value that is not checked.
If
_tokenContract
is a token that does not revert on failure, this call could fail silently, allowing the rest of the function to execute as if the transfer were successful.Similarly,
BNB
just like ZRX does not revert on failure, instead it simply returns a bool value that is not checked too: https://etherscan.io/token/0xB8c77482e45F1F44dE1745F52C74426C631bDD52Now in the current scope, Unsafe transfers are used in _lock and unlock functions.
Since these attempts to transfer could silently fail, this then leads to multiple scenarios like:
Loss of Funds: If a user attempts to lock tokens using a token that does not revert on failure, and the transferFrom operation fails silently, the user might still believe their tokens are successfully locked. Albeit, due to the lack of actual token transfer, the user's tokens would not be properly recorded in the contract's state. This could lead to the user losing access to their tokens indefinitely, as the contract would not recognize them as being locked.
Incorrect Rewards Calculation: The LockManager contract calculates rewards based on the amount of tokens locked and the duration of the lock. If the token transfer fails but the contract proceeds as if it succeeded, the reward calculations could be skewed, resulting in users receiving less than what they are entitled to.
Inability to Unlock Tokens: Since the contract relies on accurate tracking of locked tokens to facilitate unlocking, a failed transfer could mean that the contract's state does not reflect the user's intention to lock tokens. Consequently, the user might find themselves unable to unlock their tokens, effectively leading to loses.
Tools Used
Manual review
Recommended Mitigation Steps:
Ensure that the return value of
transferFrom
is always checked, and the transaction is reverted if the transfer fails Or use openzeppelin'sSafeERC20
's libraryAssessed type
ERC20