Open sherlock-admin opened 1 year ago
Escalate for 1 USDC
Causes total loss of funds for LPs when this happens. High risk
Escalate for 1 USDC
Causes total loss of funds for LPs when this happens. High risk
You've created a valid escalation for 1 USDC!
To remove the escalation from consideration: Delete your comment. To change the amount you've staked on this escalation: Edit your comment (do not create a new comment).
You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final.
Escalation accepted
Escalation accepted
This issue's escalations have been accepted!
Contestants' payouts and scores will be updated according to the changes made on this issue.
rvierdiiev
high
Possible to fully block PublicVault.processEpoch function. No one will be able to receive their funds
Summary
Possible to fully block
PublicVault.processEpoch
function. No one will be able to receive their fundsVulnerability Detail
When liquidity providers want to redeem their share from
PublicVault
they callredeemFutureEpoch
function which will create newWithdrawProxy
for the epoch(if not created already) and then mint shares for redeemer inWithdrawProxy
. PublicVault transfer user's shares to himself.https://github.com/sherlock-audit/2022-10-astaria/blob/main/src/PublicVault.sol#L178-L212
This function mints
WithdrawProxy
shares 1:1 to redeemedPublicVault
shares. Then later after call ofprocessEpoch
andtransferWithdrawReserve
the funds will be sent to the WithdrawProxy and users can now redeem their shares from it.Function
processEpoch
decides how many funds should be sent to theWithdrawProxy
.https://github.com/sherlock-audit/2022-10-astaria/blob/main/src/PublicVault.sol#L268-L289
This is how it is decided how much money should be sent to WithdrawProxy. Firstly, we look at totalSupply of WithdrawProxy.
uint256 proxySupply = WithdrawProxy(withdrawProxies[currentEpoch]).totalSupply();
.And then we convert them to assets amount.
uint256 withdrawAssets = convertToAssets(proxySupply);
In the end function burns
proxySupply
amount of shares controlled by PublicVault._burn(address(this), proxySupply);
Then this amount is allowed to be sent(if no auctions currently, but this is not important right now).
This all allows to attacker to make
WithdrawProxy.deposit
to mint new shares for him and increase totalSupply of WithdrawProxy, soproxySupply
becomes more then was sent toPublicVault
.This is attack scenario.
1.PublicVault is created and funded with 50 ethers. 2.Someone calls
redeemFutureEpoch
function to create new WithdrawProxy for next epoch. 3.Attacker sends 1 wei to WithdrawProxy to make totalAssets be > 0. Attacker deposit to WithdrawProxy 1 wei. Now WithdrawProxy.totalSupply > PublicVault.balanceOf(PublicVault). 4.Someone callprocessEpoch
and it reverts on burning.As result, nothing will be send to WithdrawProxy where shares were minted for users. The just lost money.
Also this attack can be improved to drain users funds to attacker. Attacker should be liquidity provider. And he can initiate next redeem for next epoch, then deposit to new WithdrawProxy enough amount to get new shares. And call
processEpoch
which will send to the vault amount, that was not sent to previous attacked WithdrawProxy, as well. So attacker will take those funds.Impact
Funds of PublicVault depositors are stolen.
Code Snippet
This is simple test that shows how external actor can corrupt WithdrawProxy.
Tool used
Manual Review
Recommendation
Make function WithdrawProxy.deposit not callable.