Closed sherlock-admin2 closed 2 months ago
Invalid, a user expects to be max locked until max lock is disabled, afterwhich only then the duration of lock time will commence i.e., as long as you have a tokenId to with max_lock enabled, you are expecting to be always max locked for that tokenId
dev0cloo
High
Incorrect Logic in _isApprovedOrOwner() Function Leads to Unintended Lock Extension, Allows Lock Manipulation and Prevents Expired Lock Withdrawals
Summary
Incorrect logic in the
_isApprovedOrOwner()
function leads to multiple unwanted scenarios where the lock time for certain users is increased any time the function is called. In some cases, it prevents users whose locks have expired from withdrawing their locked tokens. This is due to themax_lock()
function being called in_isApprovedOrOwner()
.Vulnerability Detail
From the snippet above, the function first makes a call to
max_lock()
every time it is called. Themax_lock()
function on the other hand, sets the unlock time for a given tokenID to the max lock time (i.e 52 weeks or a year). This, however, only succeeds if the tokenID owner has enabled max lock for the tokenID (i. emaxLockIdToIndex != 0
) and the protocol hasmax_lock_enabled
set totrue
(This is enabled by default). This is seen in the snippet belowAs
max_lock_enabled
is by default set totrue
, until it is disabled by the protocol, the issues highlighted here work with the assumption thatmax_lock_enabled
istrue
. The issues start when a user who has enabled max lock on their tokenID performs any action which calls_isApprovedOrOwner()
as the unlock time for that tokenID will always be refreshed to a year later. The following are some functions impacted by this vulnerability and it's effects:withdraw()
: Unable to withdraw locked tokens due torequire(_locked.end > block.timestamp, "Lock expired");
being triggered inmax_lock()
for expired locked tokensincrease_amount()
: modifies the unlock time any time a maxlocked user wishes to increase their token balance which goes against the function comment belowdisable_max_lock()
: Further extends the unlock time before disabling Max LockisApprovedOrOwner()
: external function that allows anyone to extend the lock time of the tokenID they input if the tokenID has maxLockEnabled.The POC below shows some scenarios where this vulnerability is exploited or causes a DOS.
Unable to withdraw
[Logs]
Maliciously increasing the unlock time
[Logs]
Impact
As highlighted earlier, this vulnerability can lead to unintended lock extensions, lock manipulation by malicious actors and prevents withdrawals when the lock has expired.
Code Snippet
https://github.com/sherlock-audit/2024-06-velocimeter/blob/main/v4-contracts/contracts/VotingEscrow.sol#L295-L296
Tool used
Manual Review
Recommendation
Remove
max_lock()
function in_isApprovedOrOwner()
.