Open c4-bot-2 opened 4 months ago
Ideally the protocol doesn't provides any financial advantage (to any individual) for slashing any operator. So if a staker provides a quite low priority gas fees then it might stay in the mempool for long enough to be slashed for activity which it wasn't responsible for.
So imo the staker's should provide enough priority gas fees for finishRedeem
to prevent the aforementioned. @dewpe
Would re-rate to a non-issue
From a technical standpoint, the user can withdraw on the exact second that the 9th day hits but they could delay it forever if they really wanted. It's ultimately up to them to finish it in a timely manner. On the frontend we can state "hey a slashing has started so withdraw your funds right when the 9th day hits". In normal operations, a DSS would be written so that it slashes users from only the active operator set and that code can be reviewed by stakers and operators before depositing and delegating. If you let them out at 7 days if there isn't a slashing request then you may run into some timing games if there is a slashing request occurs then.
From a philosophical standpoint, DSS contracts would be audited and agreeing to allocate assets to them or to an operator that allocates to them means you agree to whatever slashing conditions the DSS implements. In theory the DSS can slash you for 100% right when you register if it wanted.
MiloTruck marked the issue as satisfactory
MiloTruck marked the issue as selected for report
MiloTruck changed the severity to 2 (Med Risk)
MiloTruck marked the issue as not selected for report
MiloTruck marked the issue as duplicate of #7
MiloTruck marked the issue as not a duplicate
Agree that the second scenario is unrealistic - it is entirely the staker's responsibility to ensure they withdraw their funds on time. If the staker calls finishRedeem()
with a priority fee so low that his transaction remains in the mempool for an extended period of time, it is considered a user mistake.
However, the warden does make a valid point that calculating the amount of assets to slash based on totalAssets()
will include assets queued for withdrawal.
@dewpe Isn't it an issue if the DSS ends up slashing a higher percentage of the remaining assets? For example:
requestSlashing()
to slash 50% of assets, which is calculated as 50 tokens.finalizeSlashing()
slashes the remaining 50 tokens, leaving 0 tokens in the vault.Shouldn't the calculation in requestSlashing()
exclude assets in pending withdrawals that have passed SLASHING_WINDOW
? Although in practice this isn't easy to implement.
MiloTruck marked the issue as primary issue
MiloTruck marked the issue as selected for report
@MiloTruck, the example seems apt and to mitigate it we are thinking of computing earmarkedStakes
during finalizeSlashing
, this way all the stakers that are staked will only be slashed.
Lines of code
https://github.com/code-423n4/2024-07-karak/blob/d19a4de35bcaf31ccec8bccd36e2d26594d05aad/src/interfaces/Constants.sol#L13-L16 https://github.com/code-423n4/2024-07-karak/blob/d19a4de35bcaf31ccec8bccd36e2d26594d05aad/src/entities/SlasherLib.sol#L94-L124 https://github.com/code-423n4/2024-07-karak/blob/d19a4de35bcaf31ccec8bccd36e2d26594d05aad/src/entities/SlasherLib.sol#L79-L92 https://github.com/code-423n4/2024-07-karak/blob/53eb78ebda718d752023db4faff4ab1567327db4/src/Vault.sol#L157-L188 https://github.com/code-423n4/2024-07-karak/blob/d19a4de35bcaf31ccec8bccd36e2d26594d05aad/src/entities/VaultLib.sol#L24-L38 https://github.com/code-423n4/2024-07-karak/blob/53eb78ebda718d752023db4faff4ab1567327db4/src/Core.sol#L248-L256 https://github.com/code-423n4/2024-07-karak/blob/d19a4de35bcaf31ccec8bccd36e2d26594d05aad/src/entities/SlasherLib.sol#L126-L151
Vulnerability details
Impact
According to https://github.com/code-423n4/2024-07-karak?tab=readme-ov-file#stakers,
Stakers can initiate a withdrawal, subject to a ``MIN_WITHDRAW_DELAY`` of 9 days
, andDSS can slash any malicious behavior occurring before the withdrawal initiation for up to 7 days
. SinceMIN_WITHDRAW_DELAY
equalsSLASHING_WINDOW + SLASHING_VETO_WINDOW
, the staker's withdrawal should be safe without being associated with any malicious behavior and hence not slashable when the DSS does not request any slashing against the corresponding vault within theSLASHING_WINDOW
of 7 days after such withdrawal is initiated.https://github.com/code-423n4/2024-07-karak/blob/d19a4de35bcaf31ccec8bccd36e2d26594d05aad/src/interfaces/Constants.sol#L13-L16
During the 2 day period after the
SLASHING_WINDOW
of 7 days is passed after the staker's withdrawal is initiated, such as when just couple minutes are passed after suchSLASHING_WINDOW
is reached, the staker's withdrawal cannot be finished but a malicious behavior can occur and the DSS can make a slashing request against the corresponding vault; in this situation, the staker's withdrawal mentioned previously should not be subject to such slashing though. At that time, when the DSS calls theCore.requestSlashing
function, which further calls theSlasherLib.requestSlashing
andSlasherLib.fetchEarmarkedStakes
functions, the token amount to be slashed is calculated as the DSS's allowed slashing percentage of the vault'stotalAssets()
, which includes the token amount corresponding to the staker's withdrawal. Because the staker's withdrawal should not be slashable, the token amount to be slashed actually should be the DSS's allowed slashing percentage of a value that equals the vault'stotalAssets()
minus the token amount corresponding to the staker's withdrawal. Thus, the DSS can unfairly slash more underlying token amount from the vault than it should be allowed.https://github.com/code-423n4/2024-07-karak/blob/d19a4de35bcaf31ccec8bccd36e2d26594d05aad/src/entities/SlasherLib.sol#L94-L124
https://github.com/code-423n4/2024-07-karak/blob/d19a4de35bcaf31ccec8bccd36e2d26594d05aad/src/entities/SlasherLib.sol#L79-L92
Moreover, when the
MIN_WITHDRAW_DELAY
of 9 days is passed after the staker's withdrawal is initiated, the staker can call theVault.finishRedeem
function for finishing his withdrawal request. SinceSLASHING_VETO_WINDOW
is 2 days, the DSS can call theCore.finalizeSlashing
function for finalizing its slashing request just after theMIN_WITHDRAW_DELAY
of 9 days is passed after the initiation of the staker's withdrawal if the DSS's slashing request was made when just couple minutes were passed after theSLASHING_WINDOW
for such withdrawal of the staker was reached. Because both the staker'sVault.finishRedeem
transaction and the DSS'sCore.finalizeSlashing
transaction are sent at the similar time, a malicious miner can place and execute the DSS'sCore.finalizeSlashing
transaction before the staker'sVault.finishRedeem
transaction. In this case, the staker's withdrawal can be unfairly slashed by the DSS even though it should not be slashed.https://github.com/code-423n4/2024-07-karak/blob/53eb78ebda718d752023db4faff4ab1567327db4/src/Vault.sol#L157-L188
https://github.com/code-423n4/2024-07-karak/blob/d19a4de35bcaf31ccec8bccd36e2d26594d05aad/src/entities/VaultLib.sol#L24-L38
https://github.com/code-423n4/2024-07-karak/blob/53eb78ebda718d752023db4faff4ab1567327db4/src/Core.sol#L248-L256
https://github.com/code-423n4/2024-07-karak/blob/d19a4de35bcaf31ccec8bccd36e2d26594d05aad/src/entities/SlasherLib.sol#L126-L151
Proof of Concept
The following steps can occur for the first described scenario where the DSS unfairly slashes more underlying token amount from the vault than it should be allowed.
100
underlying tokens and has only one staker who owns100
shares.50
shares.SLASHING_WINDOW
of 7 days between Day 0 and Day 7, no malicious behavior occurs, and the DSS does not request any slashing against the vault.50 * 100 / 100 = 50
underlying tokens for his withdrawal.50% * 100 = 50
underlying tokens.50% * (100 - 50) = 25
underlying tokens.MIN_WITHDRAW_DELAY
of 9 days is passed after the initiation of the staker's withdrawal so the staker finishes his withdrawal and does receive50 * 100 / 100 = 50
underlying tokens from the vault.50
underlying tokens calculated on Day 8, which is more than25
underlying tokens that it should slash, from the vault. Therefore, the DSS unfairly slashes more underlying tokens from the vault than it should be allowed.The following steps can occur for the second described scenario where the staker's withdrawal can be unfairly slashed by the DSS even though it should not be slashed.
150
underlying tokens and has two stakers in which Staker A owns100
shares and Staker B owns50
shares.100
shares.SLASHING_WINDOW
of 7 days between Day 0 and Day 7, no malicious behavior occurs, and the DSS does not request any slashing against the vault.100 * 150 / (100 + 50) = 100
underlying tokens for his withdrawal.50% * 150 = 75
underlying tokens.50% * (150 - 100) = 25
underlying tokens.MIN_WITHDRAW_DELAY
of 9 days is passed after the initiation of Staker A's withdrawal so the staker calls theVault.finishRedeem
function for finishing his withdrawal.Core.finalizeSlashing
function for finalizing the slashing.Vault.finishRedeem
transaction and the DSS'sCore.finalizeSlashing
transaction are sent at the similar time, a malicious miner places and executes the DSS'sCore.finalizeSlashing
transaction before Staker A'sVault.finishRedeem
transaction.Core.finalizeSlashing
transaction is executed, the DSS slashes75
underlying tokens calculated in Step 4, which is more than25
underlying tokens that it should slash, from the vault.Vault.finishRedeem
transaction is executed, Staker A receives100 * (150 - 75) / (100 + 50) = 50
underlying tokens, which is less than100
underlying tokens that it should receive for his withdrawal, from the vault. Therefore, Staker A's withdrawal is unfairly slashed by the DSS even though it should not be slashed.Tools Used
Manual Review
Recommended Mitigation Steps
One way to mitigate this issue is to update the
Vault.finishRedeem
function to allow the staker's withdrawal to be finished after theSLASHING_WINDOW
of 7 days is passed after such withdrawal is initiated if the DSS does not request any slashing against the corresponding vault within suchSLASHING_WINDOW
and only enforce theMIN_WITHDRAW_DELAY
of 9 days on the withdrawal if the DSS has requested to slash the corresponding vault within suchSLASHING_WINDOW
.Assessed type
Timing