xanoutas/solidity-security-findings huggingface dataset:
Double transfer of coins
Audit: 2022-05-rubicon-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/peripheral_contracts/WETH9.sol#L48-L53
https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L355-L356
https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L373-L374
https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L433-L434
https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L450-L451
https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L488-L491
https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L546-L548


# Vulnerability details

## Impact
The  `withdraw()` function in WETH9.sol already calls `msg.sender.transfer(wad)` - `https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/peripheral_contracts/WETH9.sol#L48-L53` , so in functions of contracts  where `WETH9(wethAddress).withdraw(abc)` is called and `msg.sender.transfer(abc)` follows the line, would basically be calling transfer twice which would mean tokens/coins are being sent twice to the caller in one call. 
 

## Proof of Concept
Occurrences of above are in the lines:

*https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L355-L356

*https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L373-L374

*https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L433-L434

*https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L450-L451

*https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L488-L491

*https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L546-L548



## Tools Used
Manual review

## Recommended Mitigation Steps
The `msg.sender.transfer(wad)`  line can be removed from the IWETH9.sol contract
loss of funds there because there is  no check of msg.sender ==owner
Audit: 2022-05-rubicon-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/rubiconPools/BathToken.sol#L511


# Vulnerability details

## Impact
 owner ==msg.sender 
is not true because owner is paramter that you can set 
myaddress==msg.sender(is me )
then you can drain all the funds  from victims
## Proof of Concept
https://github.com/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/rubiconPools/BathToken.sol#L511
address owner is paramter in function 
        require(
            owner == msg.sender,
            "This implementation does not support non-sender owners from withdrawing user shares"
        );
and then you can drain all the funds and incentives and yield also because of no check of msg.sender.


## Tools Used
manual analysis,vscode 
## Recommended Mitigation Steps
make state variable or modifer to check the owner
Arbitrary cancellation in Ro¡ubiconRouter
Audit: 2022-05-rubicon-findings
Severity: HIGH

# Lines of code

https://github.dev/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/RubiconRouter.sol#L422-L428
https://github.dev/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/RubiconRouter.sol#L449


# Vulnerability details

## Impact
Anyone can `cancel` third party offers and take third party ether.

## Proof of Concept
When [offerForETH](https://github.dev/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/RubiconRouter.sol#L422) is called on `RubiconRouter` the `RubiconMarket.offer` method is called and an `offer` is created where the [owner](https://github.dev/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/RubiconMarket.sol#L411) is the calling contract, `RubiconMarket`.

If you want to `cancel` it using [cancelForETH](https://github.dev/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/RubiconRouter.sol#L440) the Market will check that the `msg.sender` is the owner in [can_cancel](https://github.dev/code-423n4/2022-05-rubicon/blob/521d50b22b41b1f52ff9a67ea68ed8012c618da9/contracts/RubiconMarket.sol#L354) modifier, always will be true, because the caller is `RubiconRouter` and the attacker will receive the original `pay_amt`.

## Recommended Mitigation Steps
- `RubiconMarket` need to store the original owner.
Reentrancy guards aren't working in every function in RubiconMarket due to missing synchronized modifier
Audit: 2022-05-rubicon-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/RubiconMarket.sol#L612-L624
https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/RubiconMarket.sol#L627-L635
https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/RubiconMarket.sol#L637-L652
https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/RubiconMarket.sol#L655-L675
https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/RubiconMarket.sol#L678-L693
https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/RubiconMarket.sol#L697-L709
https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/RubiconMarket.sol#L829-L907


# Vulnerability details

## Impact
Reentrancy guards aren't working in every function in RubiconMarket due to missing synchronized modifier.

Without Reentrancy guards, the contract is vulnerable to reentrancy attack which can stole all money from protocol or approved user wallet as seen in news.

https://thenewscrypto.com/huge-re-entrancy-attack-80-million-stolen-from-rari-fuse-pool/

## Proof of Concept
Overriding function replace entire function if super is not being called.
Major functions are overridden with `require(!locked, "Reentrancy attempt");` code but without `synchronized` modifier.
Without `synchronized` modifier, `locked` variable is useless because it will never being assigned.
Since `locked` variable is never assigned, `require(!locked, "Reentrancy attempt");` never revert thus reentrancy guard is broken.

Example code

```
    function offer(
        uint256 pay_amt, //maker (ask) sell how much
        ERC20 pay_gem, //maker (ask) sell which token
        uint256 buy_amt, //taker (ask) buy how much
        ERC20 buy_gem //taker (ask) buy which token
    ) public override returns (uint256) {
        require(!locked, "Reentrancy attempt");


            function(uint256, ERC20, uint256, ERC20) returns (uint256) fn
         = matchingEnabled ? _offeru : super.offer;
        return fn(pay_amt, pay_gem, buy_amt, buy_gem);
    }
```

This function has `require(!locked, "Reentrancy attempt");` but without `synchronized` modifier.

## Tools Used
Scan code by eye, and use IDE to reverse engineering

## Recommended Mitigation Steps
- Add `synchronized` modifier to all required functions that reentrancy should be prevented.
- Recheck modifier in all functions and in all files.
First depositor can break minting of shares
Audit: 2022-05-rubicon-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/rubiconPools/BathToken.sol#L569-L572


# Vulnerability details




## Impact
The first depositor is able to steal subsequent deposits by directly transferring funds to the strategy. This attack vector is the same as the following audit report:

[PrePO Audit Report](https://github.com/code-423n4/2022-03-prepo-findings/issues/27)

In general terms, the attacker deposits a small amount and will receive N shares. They then directly transfer a large amount of tokens directly to the strategy. Based on the share issuance logic, future deposits that are less than the transferred amount will receive 0 shares, effectively stealing their deposited tokens. The attacker is then able to withdraw all tokens in the strategy.

## Proof of Concept

Exploit Walkthrough:
- Attacker deposits 1 wei of WETH, receives 1 wei of strategy tokens
- Attacker directly transfers 100 ether of WETH
- New user attempts to deposit 10 ether of WETH
- Based on the share issuance logic, the new user will receive 0 shares.

```js
(totalSupply == 0) ? shares = assets : shares = (assets.mul(totalSupply)).div(_pool);
```

At this point, totalSupply = 1 wei. totalBefore will be roughly 100 WETH. valueAdded = 10 WETH.

Therefore:

1 * 10 / 100 = 0 strategy tokens

- The user's deposit is successful, meaning they have lost the deposited funds in exchange for 0 shares.
- The attacker can now withdraw all deposits using the only issued share.

## Tools Used
Manual review

## Recommended Mitigation Steps
Per the PrePO submission linked above, warden GreyArt does a great job explaining recommended mitigations.

- Uniswap V2 solved this problem by sending the first 1000 LP tokens to the zero address. The same can be done in this case i.e. when totalSupply() == 0, send the first min liquidity LP tokens to the zero address to enable share dilution.
- Ensure the number of shares to be minted is non-zero: require(_shares != 0, "zero shares minted");
- Create a periphery contract that contains a wrapper function that atomically calls initialize() and deposit()
- Call deposit() once in initialize() to achieve the same effect as the suggestion above.
First user deposits to BathToken can make LP Token too expensive for other users to join (BathToken.sol)
Audit: 2022-05-rubicon-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/rubiconPools/BathToken.sol#L557-L585
https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/rubiconPools/BathToken.sol#L756-L759


# Vulnerability details

## Impact
The first user can claim all the rewards, and maybe no1 can join the pool

## Proof of Concept
Rich user can manipulate the `deposit` function follow these steps: 
**Step 1**: Deposit 1 `underlyingtoken` to BathToken and get 1 share. 
**Step 2**: Execute a direct transfer 1M `underlyingToken` to BathToken 
==> After this step, 1 share of BathToken will cost (1M + 1) `underlyingToken`. Assume `underlyingToken` is USDC, so it will make the share too expensive for normal (poor) people to join (they will need at least 1M + 1 USDC to get 1 share ...).
==> User can claim all of the rewards when he is the first one joins the pool
 
## Tools Used
manual review 

## Recommended Mitigation Steps
Instead of calculating `underlyingBalance()` by `IERC20(underlyingToken).balanceOf(address(this))`, we can create a variable `totalUnderlyingToken` that will be increased anytime someone call `deposit()` function.
`route` array argument length is not validated 
Audit: 2022-05-rubicon-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L221


# Vulnerability details

## Impact
In `RubiconRouter.sol` the `_swap()` function is called by various core functions inside the same file. The problem is that the `route` arrays length is never checked and this is important because the `_swap()` function iterates over the length of the `route` array and calls `RubiconMarket(_market).sellAllAmount()` on every iteration. The `_swap()` simply transfers the last token inside the `route` array after the iteration but if a users adds more than 2 tokens then `sellAllAmount()` will be called for every token in the array and only the last token will be transferred at the end. 

## Proof of Concept
https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L221

## Tools Used
Manual code review 

## Recommended Mitigation Steps
There should be validation on the `route` arrays length that is passed in as an argument to the `_swap()` function and the function should fail if the array length is too large.
Anybody can cancel orders made by RubiconRouter
Audit: 2022-05-rubicon-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L440


# Vulnerability details

Anybody can cancel an offer made by [another user using RoubiconRouter].

## Impact
If a user created an offer which wasn't fully filled, anybody (including bots) can swoop in, cancel it, and get the user's funds.

## Proof of Concept
Anybody can [create an offer](https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L412) using `offerForETH`. The router does not save the offer's originator.
Then by calling 'cancelForETH', which [does not](https://github.com/code-423n4/2022-05-rubicon/blob/main/contracts/RubiconRouter.sol#L440) check who called it, anybody can sweep the user's funds.

## Recommended Mitigation Steps
Few options are there -
- Consider saving in the router the offer's originator - although that ruins the router's statelessness
- Consider adding a parameter to RubiconMarket's `offer` function (\overload) that will allow passing who can cancel the offer
- Consider removing the functionality altogether
- Consider adding a comment warning the user of the risk of using this functionality
- Consider the futility of constantly trying to chase happiness
Attacker Could Steal Almost All The Bonus Token In BathBuddy Vesting Wallet
Audit: 2022-05-rubicon-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/peripheral_contracts/BathBuddy.sol#L87


# Vulnerability details

## Background

BathBuddy is a Vesting Wallet that payout withdrawers any `bonusTokens` they may have accrued while staking in the Bath Token (e.g. network incentives/governance tokens).

BathBuddy Vesting Wallet releases a user their relative share of the pool’s total vested bonus token during the withdraw call on BathToken.sol. This vesting occurs linearly over Unix time.

It was observed that an attacker could steal almost all the `bonusTokens` in the BathBuddy Vesting Wallet.

## Proof-of-Concept

The root cause of this issue is that the amount of `bonusTokens` that a user is entitled to is based on their relative share of the pool’s total vested bonus token at the point of the withdraw call. It is calculated based on the user's "spot" share in the pool. Thus, it is possible for an attacker to deposit large amount of tokens into a BathToken Pool to gain significant share of the pool (e.g. 95%), and then withdraw the all the shares immediately. The withdraw call will trigger the `BathToken.distributeBonusTokenRewards`, and since attacker holds overwhelming amount of share in the pool, they will receive almost all the `bonusToken` in the BathBuddy Vesting wallet, leaving behind dust amount of `bonusToken` in the wallet. This could be perform in an atomic transaction and attacker can leverage on flash-loan to fund this attack.

The following shows an example of this issue:

1. A sponsor sent 1000 DAI to the BathBuddy Vesting Wallet to be used as `bonusTokens` for bathWETH pool. The vesting duration is 4 weeks.
2. Alice and Bob deposited 50 WETH and 50 WETH respectively. The total underlying asset of bathWETH is 100 WETH after depositing. Each of them hold 50% of the shares in the pool.
3. Fast forward to the last hour of the vesting period, most of the `bonusToken` have been vested and ready for the recipients to claim. In this example, estimate 998 DAI are ready to be claimed at the final hour.
4. Since Alice has 50% stake in the pool, she should have accured close to 449 DAI at this point. If she decided to withdraw all her bathWETH LP tokens at this point, she would receive close to 449 DAI as `bonusTokens`. But she choose not to withdraw yet.
5. Unfortunately, an attacker performed a flash-loan to borrow 8500 WETH, and deposit large amount of WETH into the bathWETH gain significant share of the pool, and then withdraw the all the shares immediately.
6. Since attacker hold the an overwhelming amount of shares in the pool, they will receive almost all the `bonusToken` (around 997 DAI) in the BathBuddy Vesting wallet, leaving behind dust amount of `bonusToken` in the wallet.
7. At this point, Alice decided to withdraw all her bathWETH LP token. She only received dust amount of 0.7 DAI as `bonusTokens`

The following code shows that the amount of `bonusTokens` a us
Upgraded Q -> 3 from #460 [1677510923458]
Audit: 2023-01-astaria-findings
Severity: HIGH

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

 Lines of code
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/ClearingHouse.sol#L169-L178
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/ClearingHouse.sol#L123
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/CollateralToken.sol#L538
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/CollateralToken.sol#L528-L530

Vulnerability details
Impact
The safeTransferFrom() function on the ClearingHouse is normally used when an OpenSea auction successfully ends and the required ERC20/WETH have been transferred to the ClearingHouse.

The clearing house implements its own ERC1155 token which is included in the OpenSeaa auction as a consideration. When the auction concludes a call is made to the ClearingHouse::SafeTransferFrom() function by OpenSea, triggering the further distribution of the ERC20/WETH to both the liquidator and the Vault. The ERC20 accepted as payment for the auction is derived from the identifier of the implemented ERC1155 SafeTransferFrom() function instead of the underlying asset of the vault. This means an attacker can inject the address of any ERC20 contract when calling this function (before the auction successfully ends). A fake WETH contract can be used to emulated the required balance of the clearing house to pass all the validations.

At the end of the TransferFrom() a call is made to the CollateralToken::settleAuction() thereby burning the collateral token making it inaccessible and the NFT locked in the clearing house. Any loan outstanding also cannot be paid back and the the OpenSea auction cannot accept any bids as the collateral token is burnt meaning the lenders will have lost those funds as well.
It doesn't seem to be possible for the attacker to steal the NFT from clearing house though.

Additionally a bug in the CollateralToken::settleAuction() check to see if their actually is an auction active for the NFT makes that this attack can be even done from the very start of the loan. This also makes it possible to simply use 1 wei of real WETH instead of having to deploy a fake WETH token thereby actually reducing the cost and effort needed.

Proof of Concept
The ClearingHouse::SafeTransferFrom() is a public function that can be called by anyone and doesn't have a requiresAuth modifier.

  function safeTransferFrom(
    address from, // the from is the offerer
    address to,
    uint256 identifier,
    uint256 amount,
    bytes calldata data //empty from seaport
  ) public {
    //data is empty and useless
    _execute(from, to, identifier, amount);
  }
The _execute() function derives the paymentToken from the encodedMetaData (which is the identifier used in the safeTransferFrom())
This address is then used to further determine if enough funds have been rece
Upgraded Q -> 3 from #148 [1677186744098]
Audit: 2023-01-astaria-findings
Severity: HIGH

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

 Lines of code
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/LienToken.sol#L122-L231

Vulnerability details
Impact
Detailed description of the impact of this finding.
_buyoutLien() in LienToken.sol failes to update the new PublicVault's slope, yIntercept, and s.epochData[...].liensOpenForEpoch.

Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.
Suppose a PublicVault P calls _buyoutLien() to replace an old lien A by a new lien A`. The slope, yIntercept and s.epochData[...].liensOpenForEpoch for A's payee have been modified as follows, but the function fails to update these parameters for P, the payee of A'.
Upgraded Q -> 3 from #268 [1677186221526]
Audit: 2023-01-astaria-findings
Severity: HIGH

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

 code423n4 commented on Jan 17
Lines of code
https://github.com/code-423n4/2023-01-astaria/blob/main/src/ClearingHouse.sol#L169-L178

Vulnerability details
Impact
As there is no callback in Seaport 1.1. When listing on OpenSea, Astaria adds an additional item to be received along with payment token. It is used just to trigger the safeTransferFrom function in ClearingHouse once the NFT is sold. This way, the protocol does the necessary state clean up.
As per Spearbit security review, the protocol can not detect if the call from Seaport comes from a genuine listing or auction. Astaria’s mitigation of this risk is simply to to have the ClearingHouse with checks to enforce that it has
received enough of the payment token the right asset to complete the txn (Check point 5.2.15 in the shared security review by Spearbit).
However, the protocol doesn't validate:

The passed payment token (identifier parameter that has the token address encoded).
If there is an active auction for the relevant NFT (meaning that liquidate was actually called).
This results in three potential exploits scenarios:

First Scenario > The auction will never get a successful order fulfilment
During an active auction,

A malicious actor can call safeTransferFrom passing a wrong payment token (any ERC20 token that has no value) with enough amount required by the protocol.
This cleans up the state causing the actual call from Seaport to always revert.
Therefore, the auction will never get a successful order fulfilment.
Eventually the NFT ends up with no winning bids.