An unbounded looping is implemented over the pendingStakes[]
array inside:
The consolidatePendingStakes() function which is used across major functions of the protocol like -
consolidatePendingStakes()
loops through all the pending stakes in the pool at L121:
Since there is no lower limit on the amount being staked, a griefer or malicuous competitor interested in the bringing the protocol down can create multiple pending stakes such that when consolidatePendingStakes()
anytime, it runs out of gas and results in Denial of Service.
The griefer will make the following call enough number of times -
Note that for such a small value, due to rounding-down precision loss, no minting fee is charged by the protocol. So the cost of attack would be the sum of the value of all the TSTs (or EUROs) + gas fees.
Checking this via a unit test shows that the execution fails after around 2500 pending stakes on the local network. Add this test to check (took around 5 hours to execute locally on my system) which made use of TST and cost only 0.0000000000000025 euro
:
No new user will be able to stake in the pool by calling increasePosition()
No existing user will be able to withdraw their stake by calling decreasePosition()
No existing user can be liquidated by the protocol via a call to runLiquidation()
since it internally calls distributeAssets()
which too calls consolidatePendingStakes()
No distribution of fees via distributeFees()
possible anymore.
For all practical purposes, protocol becomes non-functional and will soon go underwater due to inability to get rid of bad debts. It is to be noted that there are no admin functions which can help delete such stakes or rescue the protocol from this state.
There is also a chance that this attack be mounted by an attacker who has first taken a huge loan and upon seeing the risk of liquidation, calculates that it is cheaper to spend TSTs (or EUROs) to break the protocol instead of adding collateral to save their undercollateralized position.
Manual review
One option is to have a minimum threshold for the staked amount so that the cost of the attack goes up significantly.
Also introduce some admin functions which can be used to rescue the protocol by deleting pending stakes (by specifying a range to delete in batches instead of looping all at once), and consider returning the invested amount - fees
.
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.