The unstake
function in the Steaking contract allows users to unstake to any address, including the contract itself. When unstaking to the contract address, it creates an inconsistency between the totalAmountStaked
variable and the actual ETH balance of the contract. This discrepancy can lead to accounting errors and vulnerabilities in dependent functions, potentially compromising the integrity of the staking system.
The vulnerability exists in the unstake
function in Steaking.vy
:
When a user unstakes to the contract's address:
usersToStakes[msg.sender]
and totalAmountStaked
are reduced by _amount
.
send(_to, _amount)
transfers ETH to the contract itself.
The contract's ETH balance remains unchanged, while totalAmountStaked
is reduced.
This creates a discrepancy between totalAmountStaked
and the actual ETH balance of the contract.
Proof of Concept:
User A stakes 10 ETH.
totalAmountStaked
is now 10 ETH.
User A unstakes 5 ETH to the contract's address.
totalAmountStaked
is reduced to 5 ETH.
The contract's actual ETH balance remains 10 ETH.
Accounting Discrepancy: totalAmountStaked
becomes inconsistent with the contract's actual ETH balance.
Potential for Exploitation: An attacker could repeatedly unstake to the contract address, artificially reducing totalAmountStaked
without removing ETH from the contract.
Interference with Other Functions: Functions relying on totalAmountStaked
(e.g., depositIntoVault
) may behave incorrectly or be vulnerable to manipulation.
Misleading Contract State: The discrepancy could lead to incorrect reporting of the total staked amount, misleading users and external systems.
Potential for Further Attacks: This state inconsistency could be leveraged for more complex attacks on the staking system or connected protocols.
Risk Rating:
Likelihood: Medium (requires intentional action but is easily executable)
Impact: High (can lead to significant contract state manipulation)
Overall: High
Manual code review
Disallow Unstaking to Contract:
Add a check to prevent unstaking to the contract's own address:
Implement Pull Pattern:
Replace the direct send
with a two-step withdrawal process:
By implementing these recommendations, particularly disallowing unstaking to the contract itself and adopting a pull pattern for withdrawals, the contract can maintain consistency between totalAmountStaked
and its actual ETH balance, significantly improving its security and reliability.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.