Open code423n4 opened 1 year ago
Similar but different from https://github.com/code-423n4/2023-03-polynomial-findings/issues/103
Somehow the import should be import {IVaultToken} from "../src/interfaces/IVaultToken.sol";
(one step less), but the POC runs correctly after that.
JustDravee marked the issue as satisfactory
JustDravee changed the severity to 2 (Med Risk)
mubaris marked the issue as sponsor confirmed
JustDravee marked the issue as selected for report
JustDravee changed the severity to 3 (High Risk)
Lines of code
https://github.com/code-423n4/2023-03-polynomial/blob/aeecafc8aaceab1ebeb94117459946032ccdff1e/src/KangarooVault.sol#L269-L333
Vulnerability details
Impact
When the KangarooVault has an open position, any withdrawals that are initiated, are queued.
QueuedWithdrawals work in two steps.
VaultToken
and if (positionData.positionId != 0) adds the request to thewithdrawalQueue
.processWithdrawalQueue()
can be called to process requests in thewithdrawalQueue
that have passedminWithdrawDelay
to transfer the SUSD tokens to the user.If the processing of a
QueuedWithdraw
entry in thewithdrawalQueue
reverts, the queuedWithdrawalHead will never increase and further processing of the queue will be impossible. This means that any users that have placed a QueuedWithdraw after the reverting entry will have lost their vaultToken without receiving their SUSD.Proof of Concept
When calling the
initiateWithdrawal()
function, the user can provide an address of the receiver of funds. When processing the withdrawal queue, the contracts does all the required checks, and then transfers the SUSD to the provided user.If we look at the Synthetix sUSD token and it's target implementation we will find that the SUSD token transfer code is:
sUSD MultiCollateralSynth:L723-L739
This means any SUSD transfer to the SUSD proxy or implementation contract, will result in a revert. An attacker can use this to make a
initiateWithdrawal()
request withuser=sUSDproxy
oruser=sUSD_MultiCollateralSynth
. Any user that request a Withdrawal viainitiateWithdrawal()
after this, will lose their vault tokens without receiving their SUSD. The attacker can do this at any time, or by frontrunning a specific (large)initiateWithdrawal()
request.To test it, a check is added to the mock contract that is used for SUSD in the test scripts:
In the KangarooVault.t.sol test script, the following test was added to demonstrated the issue:
Tools Used
Manual review, forge
Recommended Mitigation Steps
The processing of withdrawalQueue should have a mechanism to handle reverting QueuedWithdraw entries. Either by skipping them and/or moving them to another
failedWithdrawals
queue.