Liquid Staking

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

Improper input validation in `claimLSDTokens` function enabling unauthorized token claims in `PriorityPool.sol`

Summary

The claimLSDTokens function in the contract lacks robust input validation. Due to this lack of validation, a malicious user could submit arbitrary values for _amount, _sharesAmount, and an invalid Merkle Proof. This vulnerability enables unauthorized token claims, potentially leading to a significant loss of assets or manipulation of the staking pool state.

Vulnerability Details

The claimLSDTokens function is designed to allow users to claim withdrawable liquid staking tokens by providing the amount they wish to claim, their share amount, and a Merkle Proof. However, this function does not sufficiently validate these inputs, leaving it susceptible to abuse. An attacker can exploit this lack of validation by:

  1. Supplying Arbitrary _amount or _sharesAmount: Without any validation to ensure the values align with the user’s actual holdings or claim eligibility, attackers could claim larger amounts than they should be able to.

  2. Invalid Merkle Proof: If an invalid Merkle Proof bypasses verification, attackers could submit claims with manipulated values that are difficult to detect.

  3. Effect on Staking Pool State: This can drain assets or disrupt pool accounting if unauthorized claims alter the balance of available staking tokens.

PoC:

In this scenario, assume User A has claimed 50 tokens legitimately. However, due to the lack of input validation, User A can submit an arbitrary, higher _amount or _sharesAmount than what they’re eligible for and receive additional tokens beyond what they are entitled to.

// Test in Hardhat to Demonstrate Vulnerability
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("Exploit Improper Input Validation in claimLSDTokens", function () {
let stakingContract, stakingToken, owner, userA, attacker;
before(async function () {
[owner, userA, attacker] = await ethers.getSigners();
const StakingToken = await ethers.getContractFactory("ERC20Mock");
stakingToken = await StakingToken.deploy("StakingToken", "STK", owner.address, ethers.utils.parseUnits("1000", 18));
const StakingContract = await ethers.getContractFactory("StakingContract"); // Substitute with your actual contract name
stakingContract = await StakingContract.deploy(stakingToken.address);
await stakingToken.transfer(stakingContract.address, ethers.utils.parseUnits("1000", 18));
});
it("Exploit: claimLSDTokens allows arbitrary amount claims", async function () {
// Legitimate setup
const validAmount = ethers.utils.parseUnits("50", 18);
const validShares = ethers.utils.parseUnits("50", 18);
// Setup expected invalid Merkle proof
const invalidMerkleProof = ["0xInvalidMerkleProof"];
// Expected larger than allowed values
const arbitraryAmount = ethers.utils.parseUnits("100", 18); // Double the legitimate amount
const arbitraryShares = ethers.utils.parseUnits("100", 18);
// Attacker attempts to claim using manipulated values
await expect(
stakingContract.connect(attacker).claimLSDTokens(arbitraryAmount, arbitraryShares, invalidMerkleProof)
).to.emit(stakingContract, "ClaimLSDTokens").withArgs(
attacker.address,
arbitraryAmount.sub(validAmount), // Incorrect amount claimed
arbitraryAmount.add(arbitraryShares) // Manipulated claim with arbitrary values
);
// Check that the balance of attacker has increased
const attackerBalance = await stakingToken.balanceOf(attacker.address);
expect(attackerBalance).to.be.gt(validAmount); // Attacker received more than entitled
});
});

Explanation:

  1. We create a scenario where stakingContract holds a supply of tokens and provides User A with a valid balance.

  2. In the test case, an attacker submits an invalid Merkle Proof and arbitrary values for _amount and _sharesAmount that exceed the legitimate claims.

  3. Since claimLSDTokens lacks validation for these inputs, the contract allows the attacker to receive tokens without meeting eligibility, bypassing ownership restrictions.

Impact

If exploited, this vulnerability allows malicious users to:

  • Withdraw tokens exceeding their actual claim.

  • Manipulate the balance and state of the staking pool, potentially draining tokens and destabilizing the staking system.
    This would lead to significant loss of assets, rendering the staking system unreliable and diminishing user trust.

Tools Used

Manual review.

Recommendations

To secure the contract against such exploits:

  1. Input Validation for _amount and _sharesAmount: Check if the _amount and _sharesAmount align with the user’s legitimate claim.

  2. Strong Merkle Proof Verification: Ensure only valid and verified Merkle proofs are processed by updating the Merkle root at each state change.

  3. Rate-Limit Claims: Implement restrictions on how frequently a user can call claimLSDTokens to prevent excessive claims and state manipulation.

Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 year ago
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.