Skip to content

Latest commit

 

History

History
84 lines (60 loc) · 4.22 KB

029.md

File metadata and controls

84 lines (60 loc) · 4.22 KB

Obedient Lava Monkey

Medium

Missing Check for Active Reserve Status Allows Borrowing from Disabled Reserves

Summary

The lack of a check to ensure the reserve is active in the executeBorrow function will cause unintended borrowing from disabled reserves, allowing users to exploit reserves that should not permit borrowing.


Root Cause

There is no validation to confirm that the reserve's status is active before processing the borrow. Reserves can be temporarily disabled for maintenance or risk management, and the absence of this check enables borrowing from reserves that should not be accessible.

Code Snippet:

DataTypes.ReserveData storage reserve = reservesData[params.asset];
// Missing reserve status validation (e.g., reserve.isActive)
reserve.updateState(reserveCache);

In the ReserveLogic library, reserves have configurations stored in the DataTypes.ReserveConfigurationMap. This includes the isActive flag, which is intended to determine whether a reserve is available for operations like borrowing, repaying, or supplying liquidity. However, BorrowLogic.executeBorrow does not check this flag before proceeding with state updates. The getActive function explicitly checks the ACTIVE_MASK bit in the reserve's configuration:

function getActive(DataTypes.ReserveConfigurationMap memory self) internal pure returns (bool) {
    return (self.data & ACTIVE_MASK) != 0;
}

This clearly indicates that reserves have an active state flag designed to enable or disable operations like borrowing or supplying liquidity. However, this state is not being validated in the executeBorrow function of BorrowLogic. From ReserveLogic.sol, reserves maintain their configurations via the ReserveConfiguration library:

reserveCache.reserveConfiguration = reserve.configuration;
reserveCache.reserveFactor = reserveCache.reserveConfiguration.getReserveFactor();

The ReserveConfiguration library provides a method (getActive) to retrieve the active status of a reserve:

function getActive(DataTypes.ReserveConfigurationMap storage self) internal view returns (bool) {
    return (self.data & ~ACTIVE_MASK) != 0;
}

When BorrowLogic.executeBorrow fetches a reserve's data, it does not validate the reserve's active status. For instance:

DataTypes.ReserveData storage reserve = reservesData[params.asset];
// Missing check for reserve.isActive or equivalent
reserve.updateState(reserveCache);

Without this validation, the protocol will process borrowing operations on a reserve that may be disabled due to maintenance, risk mitigation, or other factors, leading to unintended consequences.


Internal Pre-conditions

  1. Reserve is marked as inactive (e.g., for maintenance or risk mitigation).
  2. User attempts to borrow from the inactive reserve.

External Pre-conditions

  1. The reserve is disabled on-chain but still has sufficient liquidity.

Attack Path

  1. User identifies a reserve that is disabled but lacks an active status check in executeBorrow.
  2. The user borrows from the reserve despite it being marked as inactive.
  3. The protocol fails to enforce its intended restrictions, allowing unintended borrowing.

Impact

The protocol suffers potential financial and operational risks by enabling borrowing from reserves that are supposed to be inactive. This may lead to reserve depletion or destabilization.


Mitigation

Add a validation step in executeBorrow to ensure the reserve is active before processing the borrowing logic:

require(reserve.isActive, "Reserve is not active for borrowing");