Open sherlock-admin4 opened 6 months ago
1 comment(s) were left on this issue during the judging contest.
takarez commented:
valid; high(1)
The protocol team fixed this issue in the following PRs/commits: https://github.com/AmphorProtocol/asynchronous-vault/pull/103
The Lead Senior Watson signed off on the fix.
fugazzi
high
Claim functions don't validate if the epoch is settled
Summary
Both claim functions fail to validate if the epoch for the request has been already settled, leading to loss of funds when claiming requests for the current epoch. The issue is worsened as
claimAndRequestDeposit()
can be used to claim a deposit on behalf of any account, allowing an attacker to wipe other's requests.Vulnerability Detail
When the vault is closed, users can request a deposit, transfer assets and later claim shares, or request a redemption, transfer shares and later redeem assets. Both of these processes store the assets or shares, and later convert these when the epoch is settled. For deposits, the core of the implementation is given by
_claimDeposit()
:And for redemptions in
_claimRedeem()
:Note that in both cases the "preview" functions are used to convert and calculate the amounts owed to the user:
_convertToShares()
and_convertToAssets()
use the settled values stored inepochs[requestId]
to convert between assets and shares.However, there is no validation to check if the claiming is done for the current unsettled epoch. If a user claims a deposit or redemption during the same epoch it has been requested, the values stored in
epochs[epochId]
will be uninitialized, which means that_convertToShares()
and_convertToAssets()
will use zero values leading to zero results too. The claiming process will succeed, but since the converted amounts are zero, the users will always get zero assets or shares.This is even worsened by the fact that
claimAndRequestDeposit()
can be used to claim a deposit on behalf of any account. An attacker can wipe any requested deposit from an arbitraryaccount
by simply callingclaimAndRequestDeposit(0, account, "")
. This will internally execute_claimDeposit(account, account)
, which will trigger the described issue.Proof of concept
The following proof of concept demonstrates the scenario in which a user claims their own deposit during the current epoch:
This other proof of concept illustrates the scenario in which an attacker calls
claimAndRequestDeposit()
to wipe the deposit of another account.Impact
CRITICAL. Requests can be wiped by executing the claim in an unsettled epoch, leading to loss of funds. The issue can also be triggered for any arbitrary account by using
claimAndRequestDeposit()
.Code Snippet
https://github.com/sherlock-audit/2024-03-amphor/blob/main/asynchronous-vault/src/AsyncSynthVault.sol#L742-L756
https://github.com/sherlock-audit/2024-03-amphor/blob/main/asynchronous-vault/src/AsyncSynthVault.sol#L758-L773
Tool used
Manual Review
Recommendation
Check that the epoch associated with the request is not the current epoch.