xanoutas/solidity-security-findings huggingface dataset:
Upgraded Q -> H from #296 [1674743769839]
Audit: 2023-01-astaria-findings
Severity: HIGH

Judge has assessed an item in Issue #296 as H risk. The relevant finding follows:

 Lines of code
https://github.com/code-423n4/2023-01-astaria/blob/main/src/ClearingHouse.sol#L169

Vulnerability details
A malicious liquidator could cause the NFT auction to fail and steal the collateral after end of auction.

Impact
Anyone can act as a liquidator and trigger the liquidation of the collateral in the vault when the outstanding loan expires.
The liquidator is compensated with a liquidator fee for doing so.

However, a malicious liquidator could cause the liquidator fee (ERC20) transfer to fail, preventing the completion of the auction, even when there is a successful bid.

There are known cases where token transfer could fail and revert. For example, it could fail if the liquidator address is blacklisted by the ERC20 token (but not by the NFT).

Once the auction period is over, the liquidator will be able to claim the NFT for free. This is basically stealing the collateral as it could have been successfully auctioned at a certain price.

Proof of Concept
The attacker can call liquidate() when a outstanding loan expires. This will trigger the auction of the collateral and listing on seaport.
https://github.com/code-423n4/2023-01-astaria/blob/main/src/AstariaRouter.sol#L621

When there is a successful auction bid, a callback by seaport to safeTransferFrom() will be triggered to complete the auction process (i.e. transfer the NFT and winning bid amount).
https://github.com/code-423n4/2023-01-astaria/blob/main/src/ClearingHouse.sol#L169

The safeTransferFrom() will in turn trigger _execute(), which also contains the code to transfer the liquidator fee to the liquidator. At this point, if the liquidator fee transfer fails and revert, it will lead to an incomplete auction process. The collateral NFT will remain in the ClearingHouse.
https://github.com/code-423n4/2023-01-astaria/blob/main/src/ClearingHouse.sol#L169

The malicious liquidator could then proceed to claim NFT for free by calling liquidatorNFTClaim() after the auction ends.
https://github.com/code-423n4/2023-01-astaria/blob/main/src/CollateralToken.sol#L109

Tools Used
Recommended Mitigation Steps
Use 'pull' withdrawal instead of 'push' transfer for the liquidator transfer fee.
Manipulate the price per share value and unfair share of future users' deposits'
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://vscode.dev/github/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/PublicVault.sol#L575-L591


# Vulnerability details

## Impact
Most of the share based vault implementation will face this issue. The vault is based on the `ERC4626` where the shares are calculated based on the deposit value. By depositing large amount as initial deposit, initial depositor can influence the future depositors value. Future depositors are forced for huge value of asset to deposit. It is not practically possible for all the users. This could directly affect on the attrition of users towards this system.

https://vscode.dev/github/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/PublicVault.sol#L479-L488
https://vscode.dev/github/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/PublicVault.sol#L575-L591

## Proof of Concept
The attacker can profit from future users' deposits. While the late users will lose part of their funds to the attacker.

A malicious early user can deposit() with 1 wei of asset token as the first depositor of the ERC20 token, and get 1 wei of shares.

Then the attacker can send 10000e18 - 1 of asset tokens and inflate the price per share from 1.0000 to an extreme value of 1.0000e22 ( from (1 + 10000e18 - 1) / 1) .

As a result, the future user who deposits 19999e18 will only receive 1 wei (from 19999e18 * 1 / 10000e18) of shares token.

They will immediately lose 9999e18 or half of their deposits if they redeem() right after the deposit().

`ERC4626 implementation function mint(uint256 shares, address receiver) public virtual returns (uint256 assets) { assets = previewMint(shares); // No need to check for rounding error, previewMint rounds up. `

## Tools Used
Manual Review

## Recommended Mitigation Steps
Consider requiring a minimal amount of share tokens to be minted for the first minter, and send a portion of the initial mints as a reserve to the DAO/ burn so that the price per share can be more resistant to manipulation.once a vault is initialized (and funded), the totalSupply must remain to be greater than a certain threshold (say 1 gwei = 10^9). This way, the conversion rate will be kept being track of, even in the case that (almost) all the shares have been redeemed.
commitment.lienRequest.strategy.vault can be dffierent from the actual vault
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/main/src/AstariaRouter.sol#L486


# Vulnerability details

## Impact
The protocol doesn't check that commitment.lienRequest.strategy.vault is equal to the actual vault.
The problem with this is that commitment.lienRequest.strategy.vault and vault might be using 2 different tokens. 

https://github.com/code-423n4/2023-01-astaria/blob/main/src/VaultImplementation.sol#L394
The borrower gets the token of the actual vault

https://github.com/code-423n4/2023-01-astaria/blob/main/src/AstariaRouter.sol#L486
https://github.com/code-423n4/2023-01-astaria/blob/57c2fe33c1d57bc2814bfd23592417fc4d5bf7de/src/LienToken.sol#L849

But has to return the currency of commitment.lienRequest.strategy.vault


## Proof of Concept
Sorry I found this last minute, and I didn't have enough time to write a POC. My apologies if this turns out to be invalid.

## Tools Used
VSCode
Purchaser of a lien token may not receive payments
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/main/src/LienToken.sol#L812-L849
https://github.com/code-423n4/2023-01-astaria/blob/main/src/LienToken.sol#L900-L909
https://github.com/code-423n4/2023-01-astaria/blob/main/src/LienToken.sol#L911-L919


# Vulnerability details

## Impact

A purchaser who buys out an existing lien via buyoutLien() will not receive future payments made to that lien holder if the seller had changed the lien payee via setPayee() and if they do not change it themselves after buying.

buyoutLien() does not reset lienData[lienId].payee to either 0 or to the new owner. While the ownership is transferred, the payments made in _payment() get their payee via getPayee() which returns the owner only if the lienData[lienId].payee is set to the zero address but returns lienData[lienId].payee otherwise. This will still have the value set by the previous owner who will continue to receive the payments.

The purchaser who buys out an existing lien via buyoutLien() will not receive future payments if the previous owner had set the payee but they do not change it via setPayee() themselves after buying. Given that setPayee() is considered optional (nothing specified in spec/docs/comments) and this reset is not part of the default flow, this will lead to a loss of purchaser's anticipated payments until they realize and reset the lien payee.


## Proof of Concept

A malicious lien seller can use setPayee() to set the payee to their address of choice and continue to receive payments, even after selling, if the buyer does not realize that they have to change the payee address to themselves after buying.


## Tools Used

Manual Review

## Recommended Mitigation Steps

buyoutLien() should reset lienData[lienId].payee to either the zero address or to the new owner.
First `ERC4626` deposit can break share calculation
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/AstariaXYZ/astaria-gpl/blob/4b49fe993d9b807fe68b3421ee7f2fe91267c9ef/src/ERC4626-Cloned.sol#L107-L113


# Vulnerability details

## Impact
`ERC4626` vault share price can be maliciously inflated on the initial deposit, leading to the next depositor losing assets due to precision issues.
https://github.com/AstariaXYZ/astaria-gpl/blob/4b49fe993d9b807fe68b3421ee7f2fe91267c9ef/src/ERC4626-Cloned.sol#L107-L113
https://github.com/AstariaXYZ/astaria-gpl/blob/4b49fe993d9b807fe68b3421ee7f2fe91267c9ef/src/ERC4626-Cloned.sol#L105

## Proof of Concept
The first depositor of an `ERC4626` vault can maliciously manipulate the share price by depositing the lowest possible amount (1 wei) of liquidity and then artificially inflating `ERC4626.totalAssets.`

This can inflate the base share price as high as 1:1e18 early on, which force all subsequence deposit to use this share price as a base and worst case, due to rounding down, if this malicious initial deposit front-run someone else depositing, this depositor will receive 0 shares and lost his deposited assets.

Given a vault with DAI as the underlying asset:

Alice (attacker) deposits initial liquidity of 1 wei DAI via deposit()
Alice receives 1e18 (1 wei) vault shares
Alice transfers 1 ether of DAI via transfer() to the vault to artificially inflate the asset balance without minting new shares. The asset balance is now 1 ether + 1 wei DAI -> vault share price is now very high (= 1000000000000000000001 wei ~ 1000 * 1e18)
Bob (victim) deposits 100 ether DAI
Bob receives 0 shares
Bob receives 0 shares due to a precision issue. His deposited funds are lost.

The shares are calculated as following
`return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets());`
In case of a very high share price, due to `totalAssets()` > assets * supply, shares will be 0.


## Tools Used
Manual Review

## Recommended Mitigation Steps
This is a well-known issue, Uniswap and other protocols had similar issues when `supply == 0`.

For the first deposit, mint a fixed amount of shares, e.g. 10**decimals()
``` solidity
if (supply == 0) {
return 10**decimals;
} else {
return assets.mulDivDown(supply, totalAssets());
}
```
A malicious user can call transferWithdrawReserve() multiple times to modify s.withdrawReserve
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/main/src/PublicVault.sol#L359-L411


# Vulnerability details

## Impact
The function PublicVault.sol#transferWithdrawReserve() is meants to transfers funds from the PublicVault to the WithdrawProxy.

However, this function has no access control, anyone can call it multiple times to modify the withdrawReserve value

## Proof of Concept

A malicious actor can keep calling the function transferWthdrawReserve() before the withdrawal proxy is created.

If the underlying proxy has address(0), the transfer is not performed, but the state s.withdrawReserve is decremented.

Then user can invoke this function to always decrement the s.withdrawReserve to 0

      // prevent transfer of more assets then are available
      if (s.withdrawReserve <= withdrawBalance) {
        withdrawBalance = s.withdrawReserve;
        s.withdrawReserve = 0;
      } else {
        unchecked {
          s.withdrawReserve -= withdrawBalance.safeCastTo88();
        }
      }



## Tools Used

Manual Review

## Recommended Mitigation Steps

Implement: if the underlying withdrawProxy is address(0), revert transfer.
WithdrawProxy calculation error for tokens with decimals != 18 leads to `claim` reverting
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/WithdrawProxy.sol#L271-L273


# Vulnerability details

`withdrawRatio` has 18 decimals 

```solidity
314: s.liquidationWithdrawRatio = proxySupply
315:         .mulDivDown(1e18, totalSupply())
316:         .safeCastTo88();
317: 
318:       currentWithdrawProxy.setWithdrawRatio(s.liquidationWithdrawRatio);
```

But in `WithdrawProxy.claim`, `transferAmount` divides `withdrawRatio` by `10**ERC20(asset()).decimals()`. If the underlying token has fewer decimals than 18 (for instance 6, like USDC), the `transferAmount` will be much higher than expected (ie much greater than `balance`)


```solidity
268: if (s.withdrawRatio == uint256(0)) {
269:       ERC20(asset()).safeTransfer(VAULT(), balance);
270:     } else {
271:       transferAmount = uint256(s.withdrawRatio).mulDivDown(
272:         balance,
273:         10**ERC20(asset()).decimals()
274:       );
```

This will make the following computation underflow (as `balance < transferAmount`), leading to `balance` being much higher than expected

```solidity
276: unchecked {
277:         balance -= transferAmount;
278:       }
```

leading to the following transfer revert

```solidity
280: if (balance > 0) {
281:         ERC20(asset()).safeTransfer(VAULT(), balance);
282:       }
```

## Impact

Medium

## Tools Used

Manual Analysis

## Mitigation

```diff
268: if (s.withdrawRatio == uint256(0)) {
269:       ERC20(asset()).safeTransfer(VAULT(), balance);
270:     } else {
271:       transferAmount = uint256(s.withdrawRatio).mulDivDown(
272:         balance,
-273:         10**ERC20(asset()).decimals()
+273:         1e18
274:       );
```
`LienToken`: Lender and liquidator can collude to block auction and seize collateral
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/LienToken.sol#L849
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/LienToken.sol#L642-L643


# Vulnerability details

If a lender offers a loan denominated in an ERC20 token that blocks transfers to certain addresses (for example, the USDT and USDC blocklist), they may collude with a liquidator (or act as the liquidator themselves) to prevent loan payments, block all bids in the liquidation auction, and seize the borrower's collateral by transferring a `LienToken` to a blocked address.

`LienTokens` act as bearer assets: if a lender transfers their lien token to another address, the lien's new payee will be the `ownerOf` the token:

[`LienToken#_getPayee`](https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/LienToken.sol#L900-L909)

```solidity
  function _getPayee(LienStorage storage s, uint256 lienId)
    internal
    view
    returns (address)
  {
    return
      s.lienMeta[lienId].payee != address(0)
        ? s.lienMeta[lienId].payee
        : ownerOf(lienId);
  }
```

The payee address returned by `_getPayee` is used as the recipient address of loan repayments via `makePayment`:

[`LienToken#_payment`](https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/LienToken.sol#L849)

```solidity
    s.TRANSFER_PROXY.tokenTransferFrom(stack.lien.token, payer, payee, amount);
```

...as well as post-liquidation payments from the clearinghouse via `payDebtViaClearingHouse`:

[`LienToken#_paymentAH`](https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/LienToken.sol#L642-L643)

```solidity
    if (payment > 0)
      s.TRANSFER_PROXY.tokenTransferFrom(token, payer, payee, payment);
```

If an adversary tranfers their `LienToken` to an address that causes these attempted transfers to revert, like an address on the USDC blocklist, the borrower will be unable to make payments on their lien, the loan will eventually qualify for liquidation, and all bids in the Seaport auction will revert when they attempt to send payment to the blocklisted address.

Following the failed auction, the liquidator can call `CollateralToken#liquidatorNFTClaim`, which calls `ClearingHouse#settleLiquidatorNFTClaim` and settles the loan for zero payment, claiming the "liquidated" collateral token for free:

[`ClearingHouse#settleLiquidatorNFTClaim`](https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/ClearingHouse.sol#L220-L231)

```solidity
  function settleLiquidatorNFTClaim() external {
    IAstariaRouter ASTARIA_ROUTER = IAstariaRouter(_getArgAddress(0));

    require(msg.sender == address(ASTARIA_ROUTER.COLLATERAL_TOKEN()));
    ClearingHouseStorage storage s = _getStorage();
    ASTARIA_ROUTER.LIEN_TOKEN().payDebtViaClearingHouse(
      address(0)
First ERC4626 deposit can break share calculation
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/AstariaXYZ/astaria-gpl/blob/4b49fe993d9b807fe68b3421ee7f2fe91267c9ef/src/ERC4626-Cloned.sol#L107-L113


# Vulnerability details

## Impact

The first depositor of an ERC4626 vault can maliciously manipulate the share price by depositing the lowest possible amount (1 wei) of liquidity and then artificially inflating ERC4626.totalAssets.

This can inflate the base share price as high as 1:1e18 early on, which force all subsequence deposit to use this share price as a base and worst case, due to rounding down, if this malicious initial deposit front-run someone else depositing, this depositor will receive 0 shares and lost his deposited assets.

ERC4626 vault share price can be maliciously inflated on the initial deposit, leading to the next depositor losing assets due to precision issues.

## Proof of Concept

Given a vault with DAI as the underlying asset:

Alice (attacker) deposits initial liquidity of 1 wei DAI via deposit() Alice receives 1e18 (1 wei) vault shares Alice transfers 1 ether of DAI via transfer() to the vault to artificially inflate the asset balance without minting new shares. The asset balance is now 1 ether + 1 wei DAI -> vault share price is now very high (= 1000000000000000000001 wei ~ 1000 * 1e18) Bob (victim) deposits 100 ether DAI Bob receives 0 shares Bob receives 0 shares due to a precision issue. His deposited funds are lost.

The shares are calculated as following return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets()); In case of a very high share price, due to totalAssets() > assets * supply, shares will be 0.


## Tools Used

Manual Review

## Recommended Mitigation Steps

For the first deposit, mint a fixed amount of shares, e.g. 10**decimals()


if (supply == 0) {
    return 10**decimals; 
} else {
    return assets.mulDivDown(supply, totalAssets());
}
FIRST ERC4626 DEPOSIT CAN BE EXPLOITED ON SHARE CALCULATION
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/AstariaXYZ/astaria-gpl/blob/4b49fe993d9b807fe68b3421ee7f2fe91267c9ef/src/ERC4626-Cloned.sol#L107-L113


# Vulnerability details

## Impact
This is a common attack vector involving shares based liquidity pool contracts. An early user can manipulate the price per share and profit from late users' deposits because of the precision loss caused by the rather large value of price per share.
(Note: In the case of the protocol, the price per share relates to the amount of fund (asset) tokens per share.)

[ERC4626-Cloned.sol#L107-L113](https://github.com/AstariaXYZ/astaria-gpl/blob/4b49fe993d9b807fe68b3421ee7f2fe91267c9ef/src/ERC4626-Cloned.sol#L107-L113)

```
  function convertToShares(
    uint256 assets
  ) public view virtual returns (uint256) {
    uint256 supply = totalSupply(); // Saves an extra SLOAD if totalSupply is non-zero.

    return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets());
  }
```
## Proof of Concept
Here is the exploit scenario:

1. A malicious early user can call `deposit()` with 1 wei of asset token as the first depositor, and gets 1 wei of shares as is evidenced in the ternary return statement above.

2. Next, the attacker will send 10000e18 - 1 of asset tokens and inflate the price per share from 1.0000 to an extreme value of 1.0000e22 ( from (1 + 10000e18 - 1) / 1).

3. Consequently, the future user who deposits 19999e18 will only receive 1 wei (from 19999e18 * 1 / 10000e18) of shares token.

4. He/she will immediately lose 9999e18 or equivalently half of the deposits if `redeem()` is called right after `deposit()`, albeit to be realized in the next epoch.

Conclusion: The attacker can profit from future users' deposits whilst the late users will lose part of their funds to the attacker.

## Recommended Mitigation Steps
It is recommended sending the first 1000 shares to address 0, a mitigation approach adopted by the Uniswap V2 protocol.

Additionally, the protocol should strongly advise depositors to deposit funds via AstariaRouter.sol (instead of PublicVault.sol to avoid this specific leak) that will have a slippage protection.
Proper use of dependecy 
Audit: 2023-01-astaria-findings
Severity: HIGH

# Lines of code

https://github.com/transmissions11/solmate/blob/3998897acb502fa7b480f505138a6ae1842e8d10/src/utils/SafeTransferLib.sol#L9
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/Vault.sol#L72


# Vulnerability details

## Impact
- Using `safeTransferFrom` of solmate.
- There is no checking the token address is exist

## Proof of Concept
After consulting the dev, the only check for making sure the token exist is a list on the UI/fontend side.
A highly motivated attacker can easily disable the UI/frontend mechanisms 
and deposit a token that is not support at the time,
Later when it is supported, the attacker can withdraw.
## Tools Used
None

## Recommended Mitigation Steps
Use Openzeppelin safeTransferFrom or check the token contract exists.