merlinboii - The attacker will prevent eligible users from claiming the liquidated balance #742
Labels
Sponsor Confirmed
The sponsor acknowledged this issue is valid
Will Fix
The sponsor confirmed this issue will be fixed
merlinboii
High
The attacker will prevent eligible users from claiming the liquidated balance
Summary
The
CollectionShutdown
contract has vulnerabilities allowing a malicious actor to prevent eligible users from claiming the liquidated balance after liquidation bySudoSwap
.Root Cause
CollectionShutdown::vote()
does not prevent voting after the collection shutdown is executed and/or during the claim state, allowing malicious actors to triggercanExecute
toTRUE
after execution.CollectionShutdown::cancel()
does not useparams.collectionToken
to retrieve thedenomination()
for validating the total supply during cancellation, which opens the door to manipulations that can bypass the checks.Internal pre-conditions
MAX_SHUTDOWN_TOKENS
).denomination
of the collection token for the shutdown collection is greater than 0.External pre-conditions
Attack Path
Pre-condition:
4 * 1e18 * 10 ** denom
).Attack:
Lewis notices that the collection can be shutdown and calls
CollectionShutdown::start()
.totalSupply
meets the condition<= MAX_SHUTDOWN_TOKENS
.params.quorumVotes
= 50% of totalSupply =2 * 1e18 * 1eDenom
(2 CTs).params.shutdownVotes += 2 CTs
.params.canExecute
is flagged to beTRUE
sinceparams.shutdownVotes (2CTs) >= params.quorumVotes (2 CTs)
.Time passes, no cancellation occurs, and the owner executes the pending shutdown.
params.quorumVotes
remains the same as there is no change in supply.Locker
, deleting_collectionToken[_collection]
andcollectionInitialized[_collection]
.params.canExecute
is flagged back toFALSE
.After some or all NFTs are sold on SudoSwap:
Max monitors the NFT sales and prepares for the attack.
Max splits their balance of CTs to his another wallet and remains holding a small amount to perform the attack.
Max, who never voted, calls
CollectionShutdown::vote()
to flagparams.canExecute
back toTRUE
.params.shutdownVotes >= params.quorumVotes
(due to Lewis' shutdown),params.canExecute
is set back toTRUE
.Max registers the target collection again, manipulating the token's
denomination
via theLocker::createCollection()
.denomination
lower than the previous one (e.g., previously 4, now 0).Max invokes
CollectionShutdown::cancel()
to remove all properties of_collectionParams[_collection]
, including_collectionParams[].availableClaim
.Result: This check passes, allowing Max to cancel and prevent Lewis from claiming their eligible ETH from SudoSwap.
Impact
The attack allows a malicious actor to prevent legitimate token holders from claiming their eligible NFT sale proceeds from SudoSwap. This could lead to significant financial losses for affected users.
PoC
Setup
CollectionShutdown.t::constructor()
to mint CTs token with denominator more that 0flayer/test/utils/CollectionShutdown.t.sol
forge test --mt test_CanBlockEligibleUsersToClaim -vvv
Coded PoC
Show Coded PoC
Result
Results of running the test:
Mitigation
params.canExecute
.function vote(address _collection) public nonReentrant whenNotPaused { // Ensure that we are within the shutdown window CollectionShutdownParams memory params = _collectionParams[_collection]; if (params.quorumVotes == 0) revert ShutdownProccessNotStarted(); + if (params.sweeperPool != address(0)) revert ShutdownExecuted(); _collectionParams[_collection] = _vote(_collection, params); }
The text was updated successfully, but these errors were encountered: