Closed sherlock-admin2 closed 2 months ago
Invalid, yieldvault logic is OOS of this contest. The watson also attempted to introduce new logic into the mock yield vault contracts
If the amount of yieldVault shares held by the prizeVault = 0, then totalPreciseAssets will revert since yieldVault.previewRedeem(yieldVault.balanceOf(address(this))) will revert.
This is a valid high severity issue
Root cause: transferTokensOut()
reverts when yieldVault shares owned by the prizeVault = 0 DUE TO use of totalPreciseAssets
in the calcualtion of _availableYield
, totalPreciseAssets
will revert.
Impact: = The attacker has effectively stolen the yield from other users. The attacker has reduced the chances of winning for all other users of that vault.
The attack path is clearly documented in the vulnerability detail and POC
The judge stated
yieldvault logic is OOS of this contest
Obviously yieldvault logic is OOS, BUT this issue has a root cause within the prizeVault and impacts the prizeVault depositors therefore has to be in scope
The purpose of a mock yieldVault contract is to act exactly how a live yieldVault would work when testing the protocol. I modified the mock so that is is more in line with a realistic yieldVault that will have sanity 0 checks.
Read the comments in the POC for the clear attack path. I have included it below for easy reference.
Escalate
On behalf of @0xspearmint1
Escalate
On behalf of @0xspearmint1
You've created a valid escalation!
To remove the escalation from consideration: Delete your comment.
You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final.
@0xspearmint1 can you please clarify how "yieldVault shares held by the prizeVault" can be 0? Wouldn't it also mean that the prize vault has 0 deposits? And how is it calculated, based on yieldVault
logic?
This attack is invalid for the same reason here. Also, anyone may deposit and liquidate anyway.
@WangSecurity During a liquidation the following line is hit in transferTokensOut.
We can see that inside the _withdraw function it will redeem yieldVault shares.
If you liquidate an amount large enough, it is possible to redeem all the shares ( proof in POC in issue ).
Since the price of a liquidation is NOT based on the liquidatable balance, an attacker can artificially inflate this by donating to the YV, so that the transferTokensOut
will redeem all the YV shares, for the same price.
I believe this issue is dependant on the YV calculations and how they deal with redeeming the shares there. Also, it can be fixed in the very same YV as well. Hence, I cannot accept it as a valid issue cause it depends on the logic of YV.
Planning to reject the escalation and leave the issue as it is.
@WangSecurity How did you come to that conclusion? The issue DOES NOT depend on YV logic. The is no fix in the YV to solve this.
Because it depends on YV how they handle this situation with large liquidations and its logic has to allow for the situation when the PV vault holds 0 shares, while still there are deposits. Hence, I believe it depends on YV. The decision remains the same, planning to reject the escalation and leave the issue as it is.
Result: Invalid Has duplicates
0xSpearmint1
high
An attacker can force a prizeVault into a state to delay liquidations for a greater profit
Summary
An attacker can force a prizeVault into a state to delay liquidations for a greater profit
Vulnerability Detail
transferTokensOut
is function that will always be called in the liquidation flowThe vulnerability is the use of
totalPreciseAssets
in the calculation of_availableYield
If the amount of yieldVault shares held by the prizeVault = 0, then
totalPreciseAssets
will revert sinceyieldVault.previewRedeem(yieldVault.balanceOf(address(this)))
will revert.An attacker can take advantage of this by liquidating a large amount of yield and then withdrawing their deposit to enter the required state where amount of yieldVault shares held by the prizeVault = 0.
At this point liquidations will revert due to the reasons previously mentioned
An attacker can then wait for some time and then deposit to increase yieldVault shares and then liquidate at a very cheap price since it is done via a Dutch auction
Impact
The attacker has effectively stolen the yield from other users.
The attacker has reduced the chances of winning for all other users of that vault.
Users of the vault will have a lower likelihood of winning a prize
Proof of concept
Replace the existing
BaseIntegration.t.sol
in /2024-05-pooltogether/pt-v5-vault/test/integration/BaseIntegration.t.sol with the followingUpdate the yieldVault MOCK so it is more realistic with the sanity check
Find it in /2024-05-pooltogether/pt-v5-vault/test/contracts/mock/YieldVault.sol
Now add the following ComplexLiquidationAttack.sol to /2024-05-pooltogether/pt-v5-vault/test/integration/ComplexLiquidationAttack.sol
The following foundry test test__ComplexLiquidationAttack() illustrates the attack scenario.
Run it with the following command line input
Code Snippet
https://github.com/sherlock-audit/2024-05-pooltogether/blob/1aa1b8c028b659585e4c7a6b9b652fb075f86db3/pt-v5-vault/src/PrizeVault.sol#L723
Tool used
Manual Review
Recommendation
Possibly using
_tryGetTotalPreciseAssets
in the calcualtion of_availableYield
, I did not have the time to verify if this works / is foolproof