Open sherlock-admin opened 1 year ago
@weitianjie2000
Slippage control removal is now set to uint256.max which will resolve this issue.
The original version is that it means no limit if the slippageLimit
is 0, it could bypass the slippageLimitPercent
. The fix uses type(uint256).max
to define no slippage limit.
xiaoming90
high
Existing Slippage Control Can Be Bypassed During Vault Settlement
Summary
The existing slippage control can be bypassed/disabled during vault settlement, thus allowing the trade to be executed without consideration of its slippage.
Vulnerability Detail
The
emergencySettlementSlippageLimitPercent
of the vault is set to 10% as per the environment file provided by Notional.https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/scripts/BalancerEnvironment.py#L43
When a user calls the
settleVaultEmergency
function, the vault will validate that the slippage (DynamicTradeParams.oracleSlippagePercent
) defined by the caller is within the acceptable slippage range by callingSettlementUtils._decodeParamsAndValidate
function.https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/balancer/external/Boosted3TokenAuraHelper.sol#L53
The
SettlementUtils._decodeParamsAndValidate
function will validate that the slippage (DynamicTradeParams.oracleSlippagePercent
) passed in by the caller does not exceed the designated threshold (10%). In Line 41-42, the transaction will revert if theDynamicTradeParams.oracleSlippagePercent
exceeds theslippageLimitPercent
. Note thatslippageLimitPercent
is equal toemergencySettlementSlippageLimitPercent
which is10%
.There is an edge case with the condition at Line 41. Consider the following cases:
callbackData.oracleSlippagePercent
= 9% andslippageLimitPercent
= 10%, the condition will evaluate asFalse
and transaction will not revertcallbackData.oracleSlippagePercent
= 11% andslippageLimitPercent
= 10%, the condition will evaluate asTrue
and transaction will revert because it exceeds the designated threshold.callbackData.oracleSlippagePercent
= 0% andslippageLimitPercent
= 10%, the condition will evaluate asFalse
and transaction will not revertThe problem is that when
callbackData.oracleSlippagePercent
is0%
, this effectively means that there is no slippage limit. This essentially exceeded the designated threshold (10%), and the transaction should revert instead, but it did not.https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/balancer/internal/settlement/SettlementUtils.sol#L32
Within
executeTradeWithDynamicSlippage
function, it will calculate thetrade.limit
by calling thePROXY.getLimitAmount
. Thetrade.limit
is the maximum amount of sellToken that can be sold OR the minimum amount of buyToken the contract is expected to receive from the DEX depending on whether you are performing a sell or buy.https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/trading/TradingModule.sol#L109
Within the
TradingUtils._getLimitAmount
function, when theslippageLimit
is set to0
,limitAmount
will be set totype(uint256).max
. See Line 187limitAmount
will be set to0
. See Line 207These effectively remove the slippage limit. Therefore, a malicious user can specify the
callbackData.oracleSlippagePercent
to be0%
to bypass the slippage validation check.https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/trading/TradingUtils.sol#L162
Proof-of-Concept
The following test case shows that when the slippage is set to 11% (11e6), the transaction will be reverted and fails the test. This is working as intended because the slippage (11%) exceeded the threshold (
emergencySettlementSlippageLimitPercent
=10%
).The following test case shows that when the slippage is set to 0, the transaction does not revert and passes the test. This is not working as intended because having no slippage (0) technically exceeded the threshold (
emergencySettlementSlippageLimitPercent
=10%
).Impact
Malicious users can trigger the permissionless
settleVaultEmergency
function and cause the trade to suffer huge slippage. This results in loss of assets for the vaults and their users.Code Snippet
https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/scripts/BalancerEnvironment.py#L43 https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/balancer/external/Boosted3TokenAuraHelper.sol#L53 https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/balancer/internal/settlement/SettlementUtils.sol#L32 https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/trading/TradingModule.sol#L109 https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/trading/TradingUtils.sol#L162
Tool used
Manual Review
Recommendation
Update the
SettlementUtils._decodeParamsAndValidate
function to revert if the slippage is set to zero.Appendix I - Normal and Post Maturity Vault Settlement
The
settlementSlippageLimitPercent
andpostMaturitySettlementSlippageLimitPercent
of the vault are set to 5% and 10% respectively per the environment file provided by Notional.https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/scripts/BalancerEnvironment.py#L42
When a user calls the
settleVaultNormal
orsettleVaultPostMaturity
function, the vault will validate that the slippage (DynamicTradeParams.oracleSlippagePercent
) defined by the caller is within the acceptable slippage range by callingSettlementUtils._decodeParamsAndValidate
function.https://github.com/sherlock-audit/2022-09-notional/blob/main/leveraged-vaults/contracts/vaults/MetaStable2TokenAuraVault.sol#L105
Since the same vulnerable
SettlementUtils._decodeParamsAndValidate
function is being used here, thesettleVaultNormal
andsettleVaultPostMaturity
functions are affected by this issue too.