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: 97/126
Findings: 1
Award: $0.01
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 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#L265-L267
The issue in the setLockDuration
function allows users to set an unlockTime
that is inconsistent with the intended lock duration. By basing the unlockTime
on a practically outdated lastLockTime
, the function enables users to manipulate their lock duration. This manipulation can undermine the contract's rules for token locking, leading to exploit that allows users to unlock their tokens earlier than intended or set a lock duration that does not align with the current time, impacting the fairness and integrity of the locking mechanism.
Here's the affected code in setLockDuration()
:
https://github.com/code-423n4/2024-05-munchables/blob/main/src/managers/LockManager.sol#L263-L267
uint32 lastLockTime = lockedTokens[msg.sender][tokenContract] .lastLockTime; lockedTokens[msg.sender][tokenContract].unlockTime = lastLockTime + uint32(_duration);
And, a typical exploit scenario could be as follows:
lastLockTime
is far in the past (e.g., several weeks ago).setLockDuration
with a specific _duration
, the user can set an unlockTime
that does not reflect the current block timestamp.Detailed steps:
lastLockTime
for a user's token is 50000.unlockTime
is 150000.setLockDuration
with _duration
of 50000. (100000 + 50000) == 150000
skip the following revert in setLockDuration()
.https://github.com/code-423n4/2024-05-munchables/blob/main/src/managers/LockManager.sol#L255-L261
// check they are not setting lock time before current unlocktime if ( uint32(block.timestamp) + uint32(_duration) < lockedTokens[msg.sender][tokenContract].unlockTime ) { revert LockDurationReducedError(); }
unlockTime
of 100000 could now skip the following revert in unlock()
.https://github.com/code-423n4/2024-05-munchables/blob/main/src/managers/LockManager.sol#L410-L411
if (lockedToken.unlockTime > uint32(block.timestamp)) revert TokenStillLockedError();
unlockTime
of 150000.Manual
Ensure the unlockTime
is calculated based on the current block timestamp to prevent manipulation of the lock duration.
https://github.com/code-423n4/2024-05-munchables/blob/main/src/managers/LockManager.sol#L254-L268
if (lockedTokens[msg.sender][tokenContract].quantity > 0) { // check they are not setting lock time before current unlocktime if ( uint32(block.timestamp) + uint32(_duration) < lockedTokens[msg.sender][tokenContract].unlockTime ) { revert LockDurationReducedError(); } - uint32 lastLockTime = lockedTokens[msg.sender][tokenContract] - .lastLockTime; lockedTokens[msg.sender][tokenContract].unlockTime = - lastLockTime + + uint32(block.timestamp) + uint32(_duration); }
Context
#0 - c4-judge
2024-06-04T12:41:27Z
alex-ppg marked the issue as duplicate of #89
#1 - c4-judge
2024-06-05T12:53:12Z
alex-ppg marked the issue as partial-75
#2 - c4-judge
2024-06-05T12:54:34Z
alex-ppg changed the severity to 3 (High Risk)