Liquid Staking

Stakelink
DeFiHardhatOracle
50,000 USDC
View results
Submission Details
Severity: medium
Invalid

Unauthorized Vault Removal

Summary

A vulnerability exists in the OperatorVCS.sol contract of the stake.link platform, specifically within the removeVault function. This function lacks proper access control mechanisms, allowing any address to invoke it. Consequently, unauthorized users can remove vaults without proper authorization, potentially disrupting the staking ecosystem and compromising user funds.

Vulnerability Details

Vulnerable Function: removeVault

function removeVault(uint256 _queueIndex) public {
address vault = vaultsToRemove[_queueIndex];
vaultsToRemove[_queueIndex] = vaultsToRemove[vaultsToRemove.length - 1];
vaultsToRemove.pop();
_updateStrategyRewards();
(uint256 principalWithdrawn, uint256 rewardsWithdrawn) = IOperatorVault(vault).exitVault();
totalDeposits -= principalWithdrawn + rewardsWithdrawn;
totalPrincipalDeposits -= principalWithdrawn;
uint256 numVaults = vaults.length;
uint256 index;
for (uint256 i = 0; i < numVaults; ++i) {
if (address(vaults[i]) == vault) {
index = i;
break;
}
}
for (uint256 i = index; i < numVaults - 1; ++i) {
vaults[i] = vaults[i + 1];
}
vaults.pop();
token.safeTransfer(address(stakingPool), token.balanceOf(address(this)));
}

Explanation:

  • Access Control Lacking: The removeVault function is marked as public without any access control modifiers such as onlyOwner. This omission allows any address to call the function.

  • Functionality Impact: Once a vault is queued for removal via the queueVaultRemoval function, any user can execute removeVault to permanently remove the vault from the system. This action adjusts the totalDeposits and totalPrincipalDeposits, potentially affecting the staking pool's integrity and the distribution of rewards.

Queueing Vault Removal: queueVaultRemoval

function queueVaultRemoval(uint256 _index) external {
address vault = address(vaults[_index]);
if (!IVault(vault).isRemoved()) revert OperatorNotRemoved();
for (uint256 i = 0; i < vaultsToRemove.length; ++i) {
if (vaultsToRemove[i] == vault) revert VaultRemovalAlreadyQueued();
}
vaultsToRemove.push(address(vault));
if (_index < globalVaultState.depositIndex) {
uint256 group = _index % globalVaultState.numVaultGroups;
uint256[] memory groups = new uint256[]();
groups[0] = group;
fundFlowController.updateOperatorVaultGroupAccounting(groups);
if (vaults[_index].claimPeriodActive()) {
removeVault(vaultsToRemove.length - 1);
}
}
}

Explanation:

  • Access Control Lacking: Similar to removeVault, the queueVaultRemoval function lacks access control modifiers, enabling any address to queue a vault for removal, provided the vault is already marked as removed.

  • Functionality Impact: Unauthorized users can queue any eligible vault for removal, which they can subsequently remove without authorization, leading to potential exploitation of the staking system.

Proof of Concept (PoC)

Step 1: Attacker Queues Vault Removal

// Attacker queues the removal of a specific vault
vm.prank(attacker);
operatorVCS.queueVaultRemoval(0);

Explanation:

  • vm.prank(attacker): Simulates the action of the attacker by impersonating their address.

  • queueVaultRemoval(0): The attacker queues the first vault in the vaults array for removal.

Step 2: Attacker Removes the Vault

// Attacker removes the queued vault without authorization
vm.prank(attacker);
operatorVCS.removeVault(0);

Explanation:

  • removeVault(0): The attacker invokes the removeVault function to execute the removal of the previously queued vault.

  • Outcome: The vault is removed from the vaults array, and associated deposits and rewards are adjusted accordingly, potentially leading to financial discrepancies and operational disruptions.

Impact

  • Financial Loss: Unauthorized removal of vaults can lead to the loss of staked funds and accrued rewards, directly impacting users' investments and trust in the platform.

  • Operational Disruption: The removal of vaults can disrupt the staking ecosystem, affecting reward distribution mechanisms and overall platform stability.

  • Erosion of Trust: Exploitation of this vulnerability undermines user confidence in the security and reliability of the stake.link platform, potentially deterring future participation.

Tools Used

  • Manual Review

Recommendations

  1. Implement Access Control on Critical Functions:

    • Restrict removeVault:

      function removeVault(uint256 _queueIndex) public onlyOwner {
      // Existing removal logic
      }

      Explanation: Adding the onlyOwner modifier ensures that only the contract owner can invoke the removeVault function, preventing unauthorized removals.

    • Restrict queueVaultRemoval:

      function queueVaultRemoval(uint256 _index) external onlyOwner {
      // Existing queue logic
      }

      Explanation: Similarly, restricting queueVaultRemoval ensures that only authorized entities can queue vaults for removal, maintaining the integrity of the removal process.

  2. Enhance Access Control Mechanisms:

    • Use Role-Based Access Control (RBAC): Implementing RBAC allows for more granular permission settings, enabling different levels of access for various functions based on roles.

      import "@openzeppelin/contracts/access/AccessControl.sol";
      contract OperatorVCS is AccessControl {
      bytes32 public constant REMOVAL_ROLE = keccak256("REMOVAL_ROLE");
      constructor() {
      _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
      }
      modifier onlyRemover() {
      require(hasRole(REMOVAL_ROLE, msg.sender), "Caller is not a remover");
      _;
      }
      function removeVault(uint256 _queueIndex) public onlyRemover {
      // Removal logic
      }
      }

      Explanation: By defining roles such as REMOVAL_ROLE, the contract can delegate specific permissions to designated addresses, enhancing security.

Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!