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: 57/126
Findings: 2
Award: $0.01
🌟 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.0042 USDC - $0.00
https://github.com/code-423n4/2024-05-munchables/blob/57dff486c3cd905f21b330c2157fe23da2a4807d/src/managers/LockManager.sol#L245-L272 https://github.com/code-423n4/2024-05-munchables/blob/57dff486c3cd905f21b330c2157fe23da2a4807d/src/managers/LockManager.sol#L311-L398
When a user calls setLockDuration
the unlockTime
of his tokens can be increased more than they intended.
When a user calls setLockDuration
the unlockTime
for his tokens is calculated based on their lastLockTime
which is set only when the function _lock()
is called.
Lets say Bob wants to call setLockDuration
in order to increase his lockDuration
by 1 day. Alice sees this transaction in the pool and calls lockOnBehalf
with parameters _quantity = 0, _onBehalfOf = {Bob's Address}
. After Alice's transaction goes through the new lastLockTime
of Bob's tokens will be block.timestamp
instead of some time in the past.
Now when Bob's transaction starts executing.
lockedTokens[msg.sender][tokenContract].unlockTime = lastLockTime + uint32(_duration);
unlockTime
will be bigger than it was supposed to be when Bob first called the function because lastLockTime
will be block.timestamp
instead of the time Bob locked his tokens.
Manual review
Calculate unlockTime
by passing only the increase in the lock as a variable in setLockDuration
instead of the total time. Avoid using lastLockTime
and use the previous unlockTime
to calculate the new unlockTime
Context
#0 - c4-judge
2024-06-05T12:58:56Z
alex-ppg marked the issue as partial-75
#1 - c4-judge
2024-06-05T13:00:01Z
alex-ppg changed the severity to 3 (High Risk)
🌟 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.014 USDC - $0.01
Users can shorten their lock time and have immediate access to their funds. Also they can bypass the minimumLockTime
set by the contract.
The function setLockDuration()
is supposed to allow users to only extend their current lock time by passing the new duration. The contract treats the variable _duration
in 2 different ways. The first way is as the total duration of the lock since its beginning and as the duration to add from block.timestamp
. Because of this differenece users are able to shorten their lock time.
Example:
In the beginning Alice has a lock that has the following properties: unlockTime
= 10, lastLockTime
= 0 and the current block.timestamp
= 6. She wants to change her lock time so she calls setLockDuration(5)
with the value _duration
= 5. She passes the check because 5+6>=10
That allows her to change her unlockTime
which is then calculated as lastLockTime + _duration
which is equal to 0 + 5 = 5. As a result her new unlockTime
is actually in the past and the funds are no longer locked.
This can also be done n-1 times to bypass a lock that is n units in the future.
Manual review
Change
if (uint32(block.timestamp) + uint32(_duration) < lockedTokens[msg.sender][tokenContract].unlockTime)
to
if (lastLockTime + uint32(_duration) < lockedTokens[msg.sender][tokenContract].unlockTime)
Math
#0 - c4-judge
2024-06-04T12:40:50Z
alex-ppg marked the issue as duplicate of #89
#1 - c4-judge
2024-06-05T12:53:54Z
alex-ppg marked the issue as satisfactory