xanoutas/solidity-security-findings huggingface dataset:
Missing deadline in `ExactInputSingleParams` allows pending transaction to be manipulated and executed maliciously
Audit: 2023-03-asymmetry-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/Reth.sol#L91-L101


# Vulnerability details

## Impact
`exactInputSingle(params)` function on uniswap router takes in deadline parameter but in code we have declared params as struct as follow:
```solidity
        ISwapRouter.ExactInputSingleParams memory params = ISwapRouter
            .ExactInputSingleParams({
                tokenIn: _tokenIn,
                tokenOut: _tokenOut,
                fee: _poolFee,
                recipient: address(this),
                amountIn: _amountIn,
                amountOutMinimum: _minOut,
                sqrtPriceLimitX96: 0
            });
```
But in uniswap docs as we can see the following at : https://docs.uniswap.org/contracts/v3/guides/swaps/single-swaps

```solidity
   ISwapRouter.ExactInputSingleParams memory params =
            ISwapRouter.ExactInputSingleParams({
                tokenIn: DAI,
                tokenOut: WETH9,
                fee: poolFee,
                recipient: msg.sender,
                deadline: block.timestamp,
                amountIn: amountIn,
                amountOutMinimum: 0,
                sqrtPriceLimitX96: 0
            });
```
There exist the option to pass the deadline.


As we can see there is no deadline parameter in our code struct. It can caused alot of serious problems:

1.Alice wants to swap eth for safEth
2.The transaction is submitted to the mempool, however, Alice chose a transaction fee that is too low for miners to be interested in including her transaction in a block. The transaction stays pending in the mempool for extended periods, which could be hours, days, weeks, or even longer.
3.When the average gas fee dropped far enough for Alice's transaction to become interesting again for miners to include it, her swap will be executed. In the meantime, the price of ETH could have drastically changed. She will still get 1 ETH but the safEth value of that output might be significantly lower. She has unknowingly performed a bad trade due to the pending transaction she forgot about.

An even worse way this issue can be maliciously exploited is through MEV:

1.The swap transaction is still pending in the mempool. Average fees are still too high for miners to be interested in it. The price of tokens has gone up significantly since the transaction was signed, meaning Alice would receive a lot more ETH when the swap is executed. But that also means that her maximum slippage value (sqrtPriceLimitX96 and minOut ) is outdated and would allow for significant slippage.
2.A MEV bot detects the pending transaction. Since the outdated maximum slippage value now allows for high slippage, the bot sandwiches Alice, resulting in significant profit for the bot and significant loss for Alice.

Also for the same reason it is necessary to provide the user to pass in the slippage to prevent something like this too.

## Tools Used
Manu
User can manually send FRX_ETH_ADDRESS token to SfrxEth with no losing his asset
Audit: 2023-03-asymmetry-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/SfrxEth.sol#L60-L68


# Vulnerability details

## Impact
In `SrfxEth.withdraw()`, `frxEthBalance` denotes the its balance of `FRX_ETH_ADDRESS`.
Let's think what happens if user send some `FRX_ETH_ADDRESS` token to SfrxEth before calling `SafEth.unstake()`.
(This assumes that `SfrxEth` is registered in `SafEth` with no-zero weight)
The `FRX_ETH_ADDRESS` token will be exchanged while `unstake()`, and it returns to the user in `eth`.
In this attack, the user doesn't win/loss any profit.
The only issue is that the contract emits event with large value.
This can cause other users' noisy argument - "How this man did get large ETH by unstaking small amount?".
```
// SafEth.sol#L128
emit Unstaked(msg.sender, ethAmountToWithdraw, _safEthAmount);
```

## Proof of Concept
Example attacking is here.
|Step|Activity|
|--|--|
|Step 1|Stake 1 ETH to `SafEth`|
|Step 2|Exchange 10 ETH to `FRX_ETH_ADDRESS` token|
|Step 3|Tranfer that `FRX_ETH_ADDRESS` token to `SfrxEth` contract address|
|Step 4|Unstake all tokens from `SafEth`|

(Step 4 should be done right after Step3. Or we can do these two steps in one block by using smart contract)
Then the user can get back about 11 ETH.
And the smart contract emits event `Unstaked(<user>, 10**18, 11 * 10**18)`

## Tools Used
VSCode

## Recommended Mitigation Steps
We can use just changed amount of `FRX_ETH_ADDRESS` token from redeeming in `SfrxEth.withdraw()`.
Like this:

```
// Update L60-L68 with this
    function withdraw(uint256 _amount) external onlyOwner {
        uint256 frxEthBalanceBefore = IERC20(FRX_ETH_ADDRESS).balanceOf(
            address(this)
        );
        IsFrxEth(SFRX_ETH_ADDRESS).redeem(
            _amount,
            address(this),
            address(this)
        );
        uint256 frxEthBalanceAfter = IERC20(FRX_ETH_ADDRESS).balanceOf(
            address(this)
        );
        uint256 frxEthBalance = frxEthBalanceAfter - frxEthBalanceBefore;
        ... ... ...
```
No check in swapExactInputSingleHop() function in Reth contract to check that exchange swap was successful
Audit: 2023-03-asymmetry-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/b3861c62e22b4c8df2a19d25cad8d98eaaf23a9e/contracts/SafEth/derivatives/Reth.sol#L101
https://github.com/code-423n4/2023-03-asymmetry/blob/b3861c62e22b4c8df2a19d25cad8d98eaaf23a9e/contracts/SafEth/derivatives/Reth.sol#L101
https://github.com/code-423n4/2023-03-asymmetry/blob/b3861c62e22b4c8df2a19d25cad8d98eaaf23a9e/contracts/SafEth/derivatives/Reth.sol#L177


# Vulnerability details

## Impact
The deposit function uses the swapExactInputSingleHop for the final/main swap, but since there's no check to confirm it was successful, if it failed then user's funds are in the incorrect contract/pool, and not invested as per protocol requirements. When user now wants to unstake, the withdraw function will use the incorrect pool balances.

## Proof of Concept

## Tools Used
Manual only.

## Recommended Mitigation Steps
Just a simple boolean/require check after the swap statement in the deposit function. And preferably another require check inside the swapExactInputSingleHop function at the end.
Not checked return value from `submitAndDeposit`
Audit: 2023-03-asymmetry-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/SfrxEth.sol#L94-L106


# Vulnerability details

## Impact
In `SfrxEth.sol` we have `deposit()` function.

```solidity
function deposit() external payable onlyOwner returns (uint256) {
        IFrxETHMinter frxETHMinterContract = IFrxETHMinter(
            FRX_ETH_MINTER_ADDRESS
        );
        uint256 sfrxBalancePre = IERC20(SFRX_ETH_ADDRESS).balanceOf(
            address(this)
        );
        frxETHMinterContract.submitAndDeposit{value: msg.value}(address(this)); 
        uint256 sfrxBalancePost = IERC20(SFRX_ETH_ADDRESS).balanceOf(
            address(this)
        );
        return sfrxBalancePost - sfrxBalancePre;
    }
```

The `deposit()` function allows the contract owner to deposit ETH and receive `safETH` tokens in return.

## Proof of Concept

Тhe problem here is on line 101:

```solidity
frxETHMinterContract.submitAndDeposit{value: msg.value}(address(this));
```

The function assumes that the call to `submitAndDeposit()` is successful and does not check the return value. This could be risky as the call may fail due to various reasons.

## Tools Used

Manual Review

## Recommended Mitigation Steps

Check the return value:

```solidity
(bool value, ) = frxETHMinterContract.submitAndDeposit{value: msg.value}(address(this));
        require(value, "Failed to send Ether");
```
totalWeight value can be changed by onlyOwner while other functions are still using it in important calculations at the same time
Audit: 2023-03-asymmetry-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/a8dd9399565ac608860dcadd7b16ff04aee06cb7/contracts/SafEth/SafEth.sol#L173
https://github.com/code-423n4/2023-03-asymmetry/blob/a8dd9399565ac608860dcadd7b16ff04aee06cb7/contracts/SafEth/SafEth.sol#L193


# Vulnerability details

## Impact
Since totalWeight value is used during several staking/unstaking function calculations to determine total deposit/withdraw amounts, if the onlyOwner can update this state variable during users using stake/unstake functions, it can negatively impact accuracy of calculations, cause state inconsistencies/race-conditions.

## Proof of Concept

## Tools Used
Manual only.

## Recommended Mitigation Steps
Mutex lock or similar appropriate solution.
Race-condition again: derivativeCount value can be changed/increased while several other functions that use derivativeCount in calculations, can be executed too.
Audit: 2023-03-asymmetry-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/a8dd9399565ac608860dcadd7b16ff04aee06cb7/contracts/SafEth/SafEth.sol#L177-L195
https://github.com/code-423n4/2023-03-asymmetry/blob/a8dd9399565ac608860dcadd7b16ff04aee06cb7/contracts/SafEth/SafEth.sol#L171


# Vulnerability details

## Impact
Can negatively impact the accuracy of any function calculations that heavily depend on the value of derivativeCount, and therefore can negatively impact all other resulting values down the line which depend on the calculations before them.

## Proof of Concept

## Tools Used
Manual only.

## Recommended Mitigation Steps
Implement mutex locks, so that when onlyOwner updates critical state variables that affect stake/unstake functions and many other internal/external function calculations, those functions cannot be executed.
Staking and unstaking may be temporarily DoS'd via external dependencies
Audit: 2023-03-asymmetry-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/SafEth.sol#L91
https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/SafEth.sol#L118


# Vulnerability details

Each underlying derivative token has logic to pause deposits. For example, we can see that wSteth deposits may be paused or limited:

```
// Steth - https://etherscan.io/address/0x47ebab13b806773ec2a2d16873e2df770d130b50#code
StakeLimitState.Data memory stakeLimitData = STAKING_STATE_POSITION.getStorageStakeLimitStruct();
require(!stakeLimitData.isStakingPaused(), "STAKING_PAUSED");

if (stakeLimitData.isStakingLimitSet()) {
	uint256 currentStakeLimit = stakeLimitData.calculateCurrentStakeLimit();

	require(msg.value <= currentStakeLimit, "STAKE_LIMIT");

	STAKING_STATE_POSITION.setStorageStakeLimitStruct(
		stakeLimitData.updatePrevStakeLimit(currentStakeLimit - msg.value)
	);
}
```

Similarly, withdrawals are processed via curve/uniswap pools, enforcing a minimum amount of ETH to receive given a maximum slippage. It's possible that the token price may be low enough that the swap fails.

```
// withdraw() - WstEth.sol:L60-61
uint256 minOut = (stEthBal * (10 ** 18 - maxSlippage)) / 10 ** 18;
IStEthEthPool(LIDO_CRV_POOL).exchange(1, 0, stEthBal, minOut);
```

If any of the deposits or withdrawals revert due to one of the above reasons, it's not possible to deposit or withdrawal at all until an admin changes the weights and/or changes the max slippage, potentially causing a loss of funds for users.
Cloud is testing the submission form
Audit: 2023-03-asymmetry-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/interfaces/IDerivative.sol#L14


# Vulnerability details

## Impact
This is a test.

## Proof of Concept
This is only a test. 

## Tools Used

I'm editing my finding now.

## Recommended Mitigation Steps
Malicious or hacked owner can steal the funds
Audit: 2023-03-asymmetry-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/Reth.sol#L107-L114
https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/WstEth.sol#L56-L67
https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/SfrxEth.sol#L60-L88


# Vulnerability details

## Impact

In `WstEth.sol`, `SfrxEth.sol` and `Reth.sol`  we have `withdraw()` functions.
For example check `withdraw()` in `Reth.sol`:
```solidity
function withdraw(uint256 amount) external onlyOwner { 
        RocketTokenRETHInterface(rethAddress()).burn(amount);
        // solhint-disable-next-line
        (bool sent, ) = address(msg.sender).call{value: address(this).balance}(
            ""
        );
        require(sent, "Failed to send Ether");
    }
```

This `withdraw` function allows the contract owner to withdraw a specified amount of `rETH` from the contract and receive the corresponding amount of ETH.

## Proof of Concept

In these functions, there is no additional protection against a malicious contract owner who might withdraw more funds than they are supposed to. This could result in the contract being drained of its funds, leading to losses for other users who have deposited funds into the contract.

## Tools Used

Manual Review 

## Recommended Mitigation Steps

You can implement a timelock mechanism to delay the withdrawal of funds, giving other users time to react if they believe the owner is acting maliciously.
upper bound on stake() may be low and result in DoS due to 1% min slippage if underlying pools have large amount of liquidity withdrawn
Audit: 2023-03-asymmetry-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/SafEth.sol#L91
https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/Reth.sol#L83-L102
https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/Reth.sol#L173-L183


# Vulnerability details

## Impact
While the protocol-allowed `stake()` `maxAmount` is 200 ETH, the actual `maxAmount` accepted may be much lower.
When taken to the extreme, with 0 liquidity in the underlying rETH/ETH UNI pool, `stake()` will always fail.
Similar cases apply for the CRV pools used in the SfrxETH and WstEth contracts.

## Proof of Concept
Currently, the TVL of the the rETH/ETH UNI pool is equivalent to ~$5M with 1.44k rETH and 1.43 ETH. https://info.uniswap.org/#/pools/0xa4e0faa58465a2d369aa21b3e42d43374c6f9613

In SafEth.sol, the `maxAmount` for `stake()` is set to 200 ETH here: https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/SafEth.sol#L55

In Reth.sol, the `maxSlippage` for rETH UNI swaps is set to 1% here: https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/Reth.sol#L44

Due to the 1% maxSlippage, Reth.sol's `swapExactInputSingleHop` will fail if the amount out is less than 
```
amountOutMinimum: _minOut,
```

Therefore, if a significant portion of the liquidity is withdrawn and the Reth derivative maintains a portion of the total weight, this could result in a DoS.

Again, this can be similarly applied across the CRV pools used in the SfrxEth and WstEth contracts.

## Tools Used
Manual Review

## Recommended Mitigation Steps
There are a few options for mitigation:
1. Consider allowing for larger or user-configurable amounts of slippage.
2. Perform off-chain monitoring of these pools (as well as any future pools that make use of AMMs) to ensure that the TVL does not dip to a point where the slippage would be > 1% for the configured stake `maxAmount`. In the event that TVL drops below this threshold for a given derivative's pool, use `adjustWeight()` to set that derivative's weight to 0.
3. Consider setting a lower `maxAmount` so that hitting 1% slippage is less likely even in shallower pools.
Unauthorized Liquidity Increase in `NonfungiblePositionManager`
Audit: 2024-10-ronin-findings
Severity: HIGH

# Lines of code

https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/periphery/NonfungiblePositionManager.sol#L246


# Vulnerability details

## Description

A critical access control vulnerability was discovered in the `NonfungiblePositionManager` contract within the Katana V3 protocol. The vulnerability lies in the `increaseLiquidity` function, which allows any address to increase the liquidity of a position, regardless of whether they own the position or not.

This function fails to verify if the caller has the appropriate permissions to modify the liquidity of the position associated with the provided `tokenId`. This oversight enables unauthorized users to increase liquidity on any position without ownership or approval. This behavior is highly problematic as it violates the expected permission boundaries, allowing an attacker to manipulate user positions arbitrarily.

## Vulnerability Details

- **Contract**: `NonfungiblePositionManager`
- **Function**: `increaseLiquidity`
- **Vulnerability Type**: Access Control Violation
- **Severity**: High

## Proof of Concept

The following test demonstrates the vulnerability: (in KatanaV3Pool.t.sol)

1. Define an unauthorized user and position token ID:
    ```solidity
    address unauthorized = makeAddr("unauthorized");
    uint positionTokenId;
    ```

2. Mint tokens to the unauthorized user for testing purposes in the setUp:
    ```solidity
    ERC20Mock(token0).mint(address(unauthorized), 100e18);
    ERC20Mock(token1).mint(address(unauthorized), 100e18);
    ```

3. Implement the test function to simulate unauthorized liquidity increase:
    ```solidity
    function test_unauthorizedIncreaseLiquidity() public {
        // Get initial liquidity
        (, , , , , , , uint128 initialLiquidity, , , , ) = positionManager.positions(positionTokenId);
        emit log_named_uint("Initial liquidity:", initialLiquidity);

        // Switch to unauthorized user
        vm.startPrank(unauthorized);

        // Approve tokens for unauthorized user
        ERC20Mock(token0).approve(address(positionManager), type(uint256).max);
        ERC20Mock(token1).approve(address(positionManager), type(uint256).max);

        // Attempt to increase liquidity as unauthorized user
        INonfungiblePositionManager.IncreaseLiquidityParams memory params = INonfungiblePositionManager.IncreaseLiquidityParams({
            tokenId: positionTokenId,
            amount0Desired: 1e17,
            amount1Desired: 1e17,
            amount0Min: 0,
            amount1Min: 0,
            deadline: block.timestamp + 1
        });

        // If proper access control is missing, this succeeds
        (uint128 addedLiquidity, uint256 amount0, uint256 amount1) = positionManager.increaseLiquidity(params);
        console.log("Unauthorized liquidity increase succeeded");
        emit log_named_uint("Added liquidity:", addedLiquidity);
        emit log_named_uint("Added amount0:", amount0);
Improper Initialization Logic in KatanaV3Factory Causes Failure/Dos in calling `KatanaV3Factory.sol::initialize`
Audit: 2024-10-ronin-findings
Severity: HIGH

# Lines of code

https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/core/KatanaV3Factory.sol#L34
https://github.com/ronin-chain/katana-v3-contracts/blob/03c80179e04f40d96f06c451ea494bb18f2a58fc/src/core/KatanaV3Factory.sol#L43


# Vulnerability details

**Description:** 
In KatanaV3Factory.sol, the constructor sets the beacon to address(1):
```javascript
constructor() {
  // disable initialization
@>  beacon = address(1);
}
```

This means the beacon is initialized to address(1) right from the deployment. However, the initialize function in KatanaV3Factory.sol includes a require statement that checks if the beacon is still at address(0):

```javascript
function initialize(address beacon_, address owner_, address treasury_) external {
@>  require(beacon == address(0), "KatanaV3Factory: ALREADY_INITIALIZED");
  // More code
}
```
Due to the constructor setting beacon to address(1), the initialize function will always fail because of the require(beacon == address(0)) check, causing it to revert with the error: "KatanaV3Factory: ALREADY_INITIALIZED".


**Impact:** 
This issue leads to a Denial of Service (DoS) in the initialize() function, preventing the proper setup of the beacon, owner, and treasury addresses. Without successful initialization, the contract cannot perform critical operations and is rendered unusable post-deployment.

 IMPACT: HIGH
 LIKELIHOOD: HIGH

**Proof of Concept:**
1. Deploy the KatanaV3Factory.sol contract. 
2. During deployment, the constructor sets the beacon to 
   address(1).
3. When attempting to call the initialize() function to set the beacon, owner, and treasury addresses, 
    the transaction reverts due to the require check (beacon == address(0)), throwing the error 
    "KatanaV3Factory: ALREADY_INITIALIZED."
 
**Practical Example of POC:**
1. Add this test in test/core/KatanaV3factory.sol
```
 function test_initalize() public {
    factory.initialize(address(10),address(this),address(30));

  }
```
2. Run the test. forge test --match-path test/KatanaV3Factory.t.sol

3. You will see that this failed with an error message : "[FAIL. Reason: revert: KatanaV3Factory: ALREADY_INITIALIZED] test_initalize() (gas: 6767)"  

**Recommended Mitigation:** 
To fix this issue, you can consider either of the following options:

1. Adjust the constructor logic:
Set the beacon to address(0) in the constructor so that it passes the require check during initialization.

```diff

constructor() {
  // disable initialization
- beacon = address(1);
+ beacon = address(0);
}
```
  OR

2. Use OpenZeppelin’s _disableInitializers function:
This function is designed to disable all initializers, ensuring that the contract cannot be initialized multiple times. You can use this approach if you're working with the OpenZeppelin framework and want to prevent reinitialization in a more standardized way.

```javascript

import "@openzeppelin/contracts/proxy/utils/Initializable.sol";

constructor() {