xanoutas/solidity-security-findings huggingface dataset:
Missing Access Control on setRouter function in DcntETH.sol
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L20-L22


# Vulnerability details

## Impact
The `setRouter` function does not restrict who can set the router address due to lack of access control. An attacker could call this function and set a malicious router, which could then call the [mint](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L24-L26) and [burn](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L28-L30) functions by easily bypassing the `onlyRouter` modifier check.


## Tools Used
Manual Review
## Recommended Mitigation Steps
Restrict the setRouter function with onlyOwner modifier so that it is only callable by the contract owner


## Assessed type

Access Control
Anyone can set the Router address in DcntEth
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L20-L22


# Vulnerability details

## Impact

Lack of modifier in `DcntEth` allows anyone to change the router address. Since the router has permissions to mint and burn from any address, this can cause loss of funds and complete devaluation of the token.

## Proof of Concept

https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L20-L22

```solidity
function setRouter(address _router) public {
        router = _router;
    }
```

## Tools Used

Manual Review

## Recommended Mitigation Steps

Add an `onlyRouter` modifier


## Assessed type

Access Control
Re-entrancy in execute function of UTBExecutor contract
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-decent/blob/011f62059f3a0b1f3577c8ccd1140f0cf3e7bb29/src/UTBExecutor.sol#L41


# Vulnerability details

## Impact
The UTBExecutor contract exhibits a re-entrancy vulnerability within its execute function. This vulnerability allows an attacker to steal all the ether present in the UTBExecutor contract, resulting in a loss of funds. The attack involves the creation of a customized contract that invokes the "receiveFromBridge" function of the UTBExecutor contract from an attacker-controlled function. During this function call, the attacker sets the customized contract as the target and uses an arbitrary value as extraNative, triggering a potential payable fallback.

## Proof of Concept
the attacker will create a custom contract that will allow the "receiveFromBridge" function to be called from one of his attacker's functions, here he will set the attacker's custom contract itself as the parameters of the "receiveFromBridge" function as the target, once the function call has been made and set as extraNative a value like 1, this will recall the target of the contract and in doing so will call a potential payable fallback which will give the attacker the possibility to execute any command again without the balance of the chosen token changing, I recommend using a reentrancyGuard modifier in the function

## Tools Used
manual review

## Recommended Mitigation Steps
To address this vulnerability, it is recommended to implement a reentrancyGuard modifier in the execute function of the UTBExecutor contract. The reentrancyGuard modifier should be designed to prevent re-entrancy attacks by ensuring that the function's state changes are completed before allowing any external calls.


## Assessed type

Invalid Validation
Incorrect sharedDecimals value can prevent bridging between EVM and Non-EVM chains
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L15


# Vulnerability details

## Impact
As mentioned in the README and confirmed by the sponsors, all chains supported by LayerZero should be considered in scope. The issue this report is pointing out is the incorrect hardcoded setting of sharedDecimals to 18 decimals. This would set the ld2sdRate to be 1 based on the code below:

```solidity
File: OFTV2.sol
19:         ld2sdRate = 10**(decimals - _sharedDecimals); // 10**0 = 1
```

The impact of this is that it would prevent bridging of tokens from evm to non evm chains in the near future.

## Proof of Concept

Since the rate used will be 1, the _sendAndCall() function in the OFTCoreV2.sol contract would cause an issue for non-evm chains. This is because non EVM chains such as Aptos/Solana use Uint64 to represent balance. To account for this, OFTV2 uses Shared Decimals for value transfers to normalize the data type difference. 
It is recommended to use a smaller shared decimal point on all chains so that the token can have a larger balance. 
For example, if the decimal point is 18, then you can not have more than approximately 18 * 10^18 tokens bounded by the uint64.max (see [here](https://layerzero.gitbook.io/docs/evm-guides/contract-standards/oft-overview/v1-oft-vs-v2-oft-which-should-i-use#what-are-the-differences-between-these-versions)).

```solidity
File: OFTCoreV2.sol
229:     function _ld2sd(uint _amount) internal view virtual returns (uint64) {
230:         uint amountSD = _amount / _ld2sdRate();
231:         require(amountSD <= type(uint64).max, "OFTCore: amountSD overflow");
232:         return uint64(amountSD);
233:     }
```

If the token balance is maxed out on any chain, this would prevent bridging since no tokens would be able to be minted through _creditTo().

## Tools Used
Manual Review

## Recommended Mitigation Steps
LayerZero recommends using the smallest decimal count used on any chain - [see here](https://layerzero.gitbook.io/docs/evm-guides/oft-walkthrough#what-should-i-set-as-shared-decimals)


## Assessed type

ERC20
Lack of access control in DcntEth.sol:setRouter() makes possible for indefinite mint and burn
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L20-L22


# Vulnerability details

## Impact
The lack of access control on `setRouter` allows an attacker to change the address of the *router* variable.

```solidity
    function setRouter(address _router) public {
        router = _router;
    }
```

Because of this, the `mint` and `burn` functions can be called by anyone who sets the router, bypassing the modifier onlyRouter.

```solidity
    function mint(address _to, uint256 _amount) public onlyRouter {
        _mint(_to, _amount);
    }
```

```solidity
    function burn(address _from, uint256 _amount) public onlyRouter {
        _burn(_from, _amount);
    }
```

```solidity
    modifier onlyRouter() {
        require(msg.sender == router);
        _;
    }
```


## Proof of Concept

Put this test file inside the tests on `src/lib/decent-bridge`

Then run `forge test --mt testAttack`
```javascript
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {ERC20} from "solmate/tokens/ERC20.sol";
import {UTB, SwapInstructions, SwapAndExecuteInstructions, FeeStructure} from "../src/UTB.sol";
import {UTBExecutor} from "../src/UTBExecutor.sol";
import {UniSwapper} from "../src/swappers/UniSwapper.sol";
import {SwapParams} from "../src/swappers/SwapParams.sol";
import {XChainExactOutFixture} from "./helpers/XChainExactOutFixture.sol";



contract UTBExactOutRoutesTest is XChainExactOutFixture {
    function setUp() public {
        src = optimism;
        dst = arbitrum;
        preSlippage = 2;
        postSlippage = 3;
        initialEthBalance = 1 ether;
        initialUsdcBalance = 10e6;
        MINT_GAS = 9e5;

        setRuntime(ENV_FORGE_TEST);
        loadAllChainInfo();
        setupUsdcInfo();
        setupWethHelperInfo();
        loadAllUniRouterInfo();
        setSkipFile(true);
        vm.label(alice, "alice");
        vm.label(bob, "bob");
    }


    function attackScenarioForSwapAndExecute() public {
        string memory chain = arbitrum;
        (
            UTB utb,
            /*UTBExecutor executor*/,
            UniSwapper swapper,
            ,
            ,

        ) = deployUTBAndItsComponents(chain);
        uint256 slippage = 1;

        address weth = getWeth(chain);
        address usdc = getUsdc(chain);

        cat = deployTheCat(chain);
        uint usdcOut = cat.price();

        (SwapParams memory swapParams, uint expected) = getSwapParamsExactOut(
            chain,
            weth,
            usdc,
            usdcOut,
            slippage
        );

        address payable refund = payable(alice);

        SwapInstructions memory swapInstructions = SwapInstructions({
            swapperId: swapper.getId(),
            swapPayload: abi.encode(swapParams, address(utb), refund)
        });

        mintWethTo(chain, alice, swapParams.amountIn);
        startImpersonating(alice);
        ERC20(weth).approve(address(utb), swap
User can take out all the tokens from Uniswapper.sol at any time
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-decent/blob/main/src/swappers/UniSwapper.sol#L123-L141
https://github.com/code-423n4/2024-01-decent/blob/main/src/swappers/UniSwapper.sol#L143-L169


# Vulnerability details

## Impact
The malicious user can take out all the tokens from UniSwapper.sol using the functions `swapExactOut()` and `swapExactIn()`

## Proof of Concept
The functions `swapExactOut()` and `swapExactIn()` have the logic to send the `path` of swapping tokens to the `swap_router` and then sending the tokens to the recipient.
But the functions miss the logic for validating that `swapParams.tokenOut` should be same as the last token of the `path` provided to the `swap_router`. This can lead to the swap_router swapping to token(specified by the path) other than `swapParams.tokenOut`.
```Solidity
IV3SwapRouter.ExactInputParams memory params = IV3SwapRouter
            .ExactInputParams({
                path: swapParams.path,
                recipient: address(this),
                amountIn: swapParams.amountIn,
                amountOutMinimum: swapParams.amountOut
            });

        IERC20(swapParams.tokenIn).approve(uniswap_router, swapParams.amountIn);
        amountOut = IV3SwapRouter(uniswap_router).exactInput(params);

        _sendToRecipient(receiver, swapParams.tokenOut, amountOut);
```

The malicious user can set the `swapParams.tokenOut` to be the token that they want to steal from `Uniswapper.sol` and the `path` so that they can maximize the number of tokens that are coming after the swap.

The `amountOut` number of `swapParams.tokenOut` tokens are send to the reciever(user).

## Tools Used
Manual Review

## Recommended Mitigation Steps
Consider setting these functions`swapExactOut()` and `swapExactIn()` as internal since these are called by the function `swap()` which also validates the input params.


## Assessed type

Other
An attacker can block message channels between two chains due to missing check of minimum gas passed in `bridgeAndExecute()` resulting in DoS
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L80


# Vulnerability details

## The vulnerability
The root cause of the vulnerability exists in the [`DecentEthRouter::_getCallParams()`](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L80) internal function which is responsible for configuring the adapter parameters which will be sent to Layerzero

    function _getCallParams(
        uint8 msgType,
        address _toAddress,
        uint16 _dstChainId,
        uint64 _dstGasForCall,
        bool deliverEth,
        bytes memory additionalPayload
    )
        private
        view
        returns (
            bytes32 destBridge,
            bytes memory adapterParams,
            bytes memory payload
        )
    {
        uint256 GAS_FOR_RELAY = 100000;
        uint256 gasAmount = GAS_FOR_RELAY + _dstGasForCall;
        adapterParams = abi.encodePacked(PT_SEND_AND_CALL, gasAmount);
        destBridge = bytes32(abi.encode(destinationBridges[_dstChainId]));
        if (msgType == MT_ETH_TRANSFER) {
            payload = abi.encode(msgType, msg.sender, _toAddress, deliverEth);
        } else {
            payload = abi.encode(
                msgType,
                msg.sender,
                _toAddress,
                deliverEth,
                additionalPayload
            );
        }
    }

The [`DecentEthRouter::_getCallParams()`](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L80) function takes the value of the parameter `_dstGasForCall` (which is user supplied) and adds it to the pre-set amount of gas for the relayer (100,000) and sets the result as the amount of gas to be sent.

The issue is that the attacker can supply zero as the value of `_dstGasForCall` parameter, leading to only 100,000 gas being set which is not sufficient and will result in `StoredPayload` and the message pathway getting blocked.

The user gets to supply the value of `_dstGasForCall` parameter at the very beginning when he decides to call the function [`UTB::bridgeAndExecute()`](https://github.com/code-423n4/2024-01-decent/blob/011f62059f3a0b1f3577c8ccd1140f0cf3e7bb29/src/UTB.sol#L259) in `bridgeInstructions.additionalArgs`, and then it keeps getting passed until it reaches [`DecentEthRouter::bridgeWithPayload`](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L197) which calls the internal function [`DecentEthRouter:_bridgeWithPayload()`](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L148) which will call the [`DecentEthRouter::_getCallParams()`](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L80) which will prepare the adapter parameters for the call to
Missing Token transfer from Executor to Stargate Bridge Adaptor
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-decent/blob/main/src/bridge_adapters/StargateBridgeAdapter.sol#L183-L216
https://github.com/code-423n4/2024-01-decent/blob/main/src/bridge_adapters/DecentBridgeAdapter.sol#L127-L154


# Vulnerability details

## Impact
Current Token flow as follows: 
`UTB -> BRIDGE_ADAPTOR -> ROUTER -> EXECUTOR -> BRIDGE_ADAPTOR -> UTB`.

So for every token transfer approvals are given to corresponding contract by one another. But in case of `StargateBridgeAdapter` approval is given but tokens are not transferred from executor to Stargate bridge adaptor. In case of `DecentBridgeAdapter` this is being done here:
https://github.com/code-423n4/2024-01-decent/blob/main/src/bridge_adapters/DecentBridgeAdapter.sol#L139-L143

```solidity
    function receiveFromBridge(
        ...
    ) public onlyExecutor {
        ...

        IERC20(swapParams.tokenIn).transferFrom(
            msg.sender,
            address(this),
            swapParams.amountIn
        );

        IERC20(swapParams.tokenIn).approve(utb, swapParams.amountIn);

        IUTB(utb).receiveFromBridge(
            ...
        );
    }
```

But in case of `StargateBridgeRouter` the transfer is not performed
```solidity
    function sgReceive(
       ...
    ) external override onlyExecutor {
        ...
        SwapParams memory swapParams = abi.decode(
            postBridge.swapPayload,
            (SwapParams)
        );

        IERC20(swapParams.tokenIn).approve(utb, swapParams.amountIn);

        IUTB(utb).receiveFromBridge(
            ...
        );
    }
```
This will actually revert in cases where the approval is given but there are no tokens to transfer, this will actually create DOS.

## Tools Used
Manual Review 

## Recommended Mitigation Steps
Transfer Tokens from executor to `StargateBridgeAdapter`.
```diff
    function sgReceive(
        ...
    ) external override onlyExecutor {
        (
            SwapInstructions memory postBridge,
            address target,
            address paymentOperator,
            bytes memory utbPayload,
            address payable refund
        ) = abi.decode(
                payload,
                (SwapInstructions, address, address, bytes, address)
            );

        SwapParams memory swapParams = abi.decode(
            postBridge.swapPayload,
            (SwapParams)
        );

+       IERC20(swapParams.tokenIn).transferFrom(
+           msg.sender,
+           address(this),
+           swapParams.amountIn
+       );

        IERC20(swapParams.tokenIn).approve(utb, swapParams.amountIn);

        IUTB(utb).receiveFromBridge(
            ...
        );
    }
```


## Assessed type

Other
Missing access control on critical router function means anyone can set the router to an arbitrary address
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L20


# Vulnerability details

There is a missing access control in `DcntEth::setRouter` that allows anyone to call the `setRouter` function, passing an arbitrary address which is then used as the router across system calls. 

## Impact
Anyone can set the router and causes undefined and unexpected behavior for the system calls as the `router`. An attacker or malicious user can gain control of the following functions: 
- `DcntEth::mint`
- `DcntEth::burn`

Attacker can mint and burn `DcntEth` which is an OFTV2 (Omni-chain fungible token) at will. 


## Proof of Concept
Add the following test to `DebugActions.t.sol` or any foundry test file. 

Don't forget to add the following imports: 



```javascript
   import {DcntEth} from "../lib/decent-bridge/src/DcntEth.sol";
   import {Test} from "forge-std/Test.sol";

  function test_MissingDecentEthAccessControl() public {
        // Deploy new DcntEth token contract.
        DcntEth dcntEth = DcntEth(address(0));

        // example amount to mint.
        uint256 UserMintAmount = 1_000_000 ether;

        // make an arbitrary user
        address arbitraryUser = makeAddr("anyUser");

        // set the router to arbitraryUser
        dcntEth.setRouter(arbitraryUser);

        // Now arbitraryUser can call router priviledged functions: mint & burn
        vm.startPrank(arbitraryUser);
        dcntEth.mint(arbitraryUser, UserMintAmount);
        dcntEth.burn(arbitraryUser, 1);

        vm.stopPrank();

        assertEq(dcntEth.balanceOf(arbitraryUser), UserMintAmount - 1);
    }
```
## Tools Used
Manual Analysis

## Recommended Mitigation Steps
Add the `onlyOwner` modifier to the `DcntEth::setRouter` function

```diff `DcntEth::setRouter`
 -  function setRouter(address _router) public {
 -       router = _router;
 -  }

 +   function setRouter(address _router) public onlyOwner {
 +       router = _router;
 +   }
```





## Assessed type

Access Control
` UniSwapper ::  swapExactIn ```  function can be called by anyone and cause a DOS attack
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-decent/blob/011f62059f3a0b1f3577c8ccd1140f0cf3e7bb29/src/swappers/UniSwapper.sol#L123


# Vulnerability details

## Impact
Anyone can call the `swapExactIn` and put in tokens that are not allowed.
This can cause a dos attack if u use tokens that are not allowed.
 
## Tools Used

manual

## Recommended Mitigation Steps
add a function modifier to the `swapExactIn`  function


## Assessed type

Access Control
Anyone can update the address of the Router in the DcntEth contract to any address they would like to set.
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L20-L22


# Vulnerability details

## Impact
By allowing anybody to set the address of the Router contract to any address they want to set it allows malicious users to get access to the mint and burn functions of the DcntEth contract.

## Proof of Concept
The [`DcntEth::setRouter() function`](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L20-L22) has not an access control to restrict who can call this function. This allows anybody to set the address of the router contract to any address they'd like to set it.
> DcntEth.sol
```solidity
//@audit-issue => No access control to restrict who can set the address of the router contract
function setRouter(address _router) public {
    router = _router;
}
```

The functions [`DcntEth::mint() function`](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L24-L26) & [`DcntEth::burn() function`](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L28-L30) can be called only by the router contract.
> DcntEth.sol
```solidity

    //@audit-info => Only the router can call the mint()
    function mint(address _to, uint256 _amount) public onlyRouter {
        _mint(_to, _amount);
    }

    //@audit-info => Only the router can call the burn()
    function burn(address _from, uint256 _amount) public onlyRouter {
        _burn(_from, _amount);
    }
```

A malicious user can set the address of the router contract to an account of their own and:
1. Gain access to mint unlimited amounts of DcntEth token, which could be used to disrupt the crosschain accounting mechanism, or to steal the deposited weth in the DecentEthRouter contract.
2. Burn all the DcntEth tokens that were issued to the DecentEthRouter contract when liquidity providers deposited their WETH or ETH into it.
3. Cause a DoS to the add and remove liquidity functions of the DecentEthRouter contract. All of these functions end up calling the [`DcntEth::mint() function`](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L24-L26) or the [`DcntEth::burn() function`](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L28-L30), if the router address is set to be different than the address of the DecentEthRouter, all the calls made from the DecentEthRouter to the DcnEth contract will revert.

> DecentEthRouter.sol
```solidity

    /// @inheritdoc IDecentEthRouter
    function addLiquidityEth()
        public
        payable
        onlyEthChain
        userDepositing(msg.value)
    {
        weth.deposit{value: msg.value}();
        
        //@audit-issue => If router in the dcnteth contract is not set to the address of the DecentEthRouter, this call will revert
        dcn