Platform: Code4rena
Start Date: 22/05/2024
Pot Size: $20,000 USDC
Total HM: 6
Participants: 126
Period: 5 days
Judge: 0xsomeone
Total Solo HM: 1
Id: 379
League: ETH
Rank: 39/126
Findings: 2
Award: $0.02
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Circolors
Also found by: 0rpse, 0x175, 0xAadi, 0xHash, 0xMax1mus, 0xMosh, 0xblack_bird, 0xdice91, 0xfox, 0xhacksmithh, 0xloscar01, 0xrex, 4rdiii, Audinarey, AvantGard, Bigsam, DPS, Dots, Drynooo, Dudex_2004, Evo, Kaysoft, King_, Limbooo, MrPotatoMagic, PENGUN, Sabit, SovaSlava, SpicyMeatball, TheFabled, Utsav, Varun_05, Walter, adam-idarrha, araj, aslanbek, ayden, bctester, biakia, bigtone, brgltd, carrotsmuggler, cats, crypticdefense, dd0x7e8, dhank, fandonov, fyamf, grearlake, iamandreiski, ilchovski, jasonxiale, joaovwfreire, lanrebayode77, m4ttm, merlinboii, niser93, nnez, octeezy, oxchsyston, pamprikrumplikas, rouhsamad, tedox, trachev, turvy_fuzz, twcctop, yotov721, zhaojohnson
0.0056 USDC - $0.01
https://github.com/code-423n4/2024-05-munchables/blob/main/src/managers/LockManager.sol#L383 https://github.com/code-423n4/2024-05-munchables/blob/main/src/managers/LockManager.sol#L290
Attacker can constantly keep increasing the unlocktime of any user without needing permission, prevent any user they wish from unlocking
The lockOnBehalf() function allows anyone to lock on behalf of any user:
function lockOnBehalf( address _tokenContract, uint256 _quantity, address _onBehalfOf ) external payable notPaused onlyActiveToken(_tokenContract) onlyConfiguredToken(_tokenContract) nonReentrant { address tokenOwner = msg.sender; address lockRecipient = msg.sender; if (_onBehalfOf != address(0)) { @> lockRecipient = _onBehalfOf; } _lock(_tokenContract, _quantity, tokenOwner, lockRecipient); }
note that there is no minimum amount required to call this function, meaning it can be calling with 1wei. Also note that there is no permission required to call the function for any user. The issue here is that on end of the _lock() function it updated the recipients unlockTime:
lockedToken.unlockTime = uint32(block.timestamp) + uint32(_lockDuration);
This allows attackers the ability to keep increasing the unlocktime of any user without needing permission, prevent any user they wish from unlocking.
Manual Review
Allow users to grant permission on who can lock onbehalf of them
Access Control
#0 - c4-judge
2024-06-05T12:58:21Z
alex-ppg marked the issue as satisfactory
🌟 Selected for report: SpicyMeatball
Also found by: 0rpse, 0xMosh, 0xblack_bird, 0xdice91, 0xhacksmithh, 0xleadwizard, 0xmystery, Audinarey, AvantGard, Bigsam, Dots, EPSec, Eeyore, Janio, Limbooo, LinKenji, Mahmud, MrPotatoMagic, Myd, Oxsadeeq, Sabit, SovaSlava, Stefanov, Tychai0s, Utsav, Varun_05, Walter, adam-idarrha, ahmedaghadi, araj, aslanbek, ayden, bigtone, c0pp3rscr3w3r, carrotsmuggler, crypticdefense, dhank, fyamf, gajiknownnothing, gavfu, itsabinashb, jasonxiale, joaovwfreire, ke1caM, leegh, merlinboii, mitko1111, n4nika, pfapostol, prapandey031, rouhsamad, sandy, snakeeaterr, stakog, steadyman, swizz, tedox, th3l1ghtd3m0n, trachev, turvy_fuzz, xyz, yashgoel72, zhaojohnson
0.0105 USDC - $0.01
https://github.com/code-423n4/2024-05-munchables/blob/main/src/managers/LockManager.sol#L257 https://github.com/code-423n4/2024-05-munchables/blob/main/src/managers/LockManager.sol#L266
People can reduce lockup times that were previously set. Breaking the core invariant of the protocol as mentioned in the doc:
The most important thing is that funds cannot get locked forever, people cannot take other people's funds, and that
people cannot reduce lockup times that are previously set.
The setLockDuration() allows users to update their lockDuration however must not be able set the new lock time before current unlocktime, this check is done here:
// check they are not setting lock time before current unlocktime if ( @> uint32(block.timestamp) + uint32(_duration) < lockedTokens[msg.sender][tokenContract].unlockTime ) { revert LockDurationReducedError(); }
Notice it uses block.timestamp
in comparing the new time in the if() condition. However, upon making the actual update it uses lastLockTime:
lockedTokens[msg.sender][tokenContract].unlockTime = lastLockTime + uint32(_duration);
This allows user to reduce their unlockTime after some time has passed.
Manual Review
Consider making this changes:
lockedTokens[msg.sender][tokenContract].unlockTime = + uint32(block.timestamp) + - lastLockTime + uint32(_duration);
Other
#0 - c4-judge
2024-06-04T12:40:53Z
alex-ppg marked the issue as duplicate of #89
#1 - c4-judge
2024-06-05T12:53:47Z
alex-ppg marked the issue as partial-75