xanoutas/solidity-security-findings huggingface dataset:
The function `THORChain_Router::_transferOutAndCallV5` is sending the ether to the `target` instead of the `recipient`.
Audit: 2024-06-thorchain-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-thorchain/blob/e3fd3c75ff994dce50d6eb66eb290d467bd494f5/ethereum/contracts/THORChain_Router.sol#L309-L311
https://github.com/code-423n4/2024-06-thorchain/blob/e3fd3c75ff994dce50d6eb66eb290d467bd494f5/ethereum/contracts/THORChain_Router.sol#L324


# Vulnerability details


## Description

In the function `THORChain_Router::_transferOutAndCallV5`, a call is performed on the target if `fromAsset` is `address(0)`, [here](https://github.com/code-423n4/2024-06-thorchain/blob/e3fd3c75ff994dce50d6eb66eb290d467bd494f5/ethereum/contracts/THORChain_Router.sol#L309-L311) and [here](https://github.com/code-423n4/2024-06-thorchain/blob/e3fd3c75ff994dce50d6eb66eb290d467bd494f5/ethereum/contracts/THORChain_Router.sol#L324).

Based on the developers comments, the call should be performed on the recipient and not the target.
` // If can't swap, just send the recipient the gas asset`

## Impact
This would result, to send the funds to the wrong address.

## Recommended Mitigation
```diff
[...]
-      (bool swapOutSuccess, ) = aggregationPayload.target.call{
+      (bool swapOutSuccess, ) = aggregationPayload.recipient.call{
        value: msg.value
      }(
[...]
      if (!swapOutSuccess) {
-        bool sendSuccess = payable(aggregationPayload.target).send(msg.value); // If can't swap, just send the recipient the gas asset
+        bool sendSuccess = payable(aggregationPayload.recipient).send(msg.value); // If can't swap, just send the recipient the gas asset
        if (!sendSuccess) {
          payable(address(msg.sender)).transfer(msg.value); // For failure, bounce back to vault & continue.
        }
      }
[...]
```


## Assessed type

ETH-Transfer
Protocol could be tricked on some to-be integrated tokens
Audit: 2024-06-thorchain-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-thorchain/blob/e3fd3c75ff994dce50d6eb66eb290d467bd494f5/bifrost/pkg/chainclients/shared/evm/smartcontract_log_parser.go#L66-L73


# Vulnerability details


## Proof of Concept

First note that this has been stated in the readMe: https://github.com/code-423n4/2024-06-thorchain/blob/e3fd3c75ff994dce50d6eb66eb290d467bd494f5/README.md#L182-L188

```markdown
### ERC20 token behaviors in scope

| Question                                                                                                                                                   | Answer |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| [Balance changes outside of transfers](https://github.com/d-xo/weird-erc20?tab=readme-ov-file#balance-modifications-outside-of-transfers-rebasingairdrops) | Yes    |
```

This means that we should take into account rebasing tokens, now from the readMe we can see that the way Thorchain is supposed to work is that it watches the router and if there is any emitted verified log, to quote unqoute the [readMe](https://github.com/code-423n4/2024-06-thorchain/blob/e3fd3c75ff994dce50d6eb66eb290d467bd494f5/README.md#L182-L188):

"
The `GetTxInItem` is run for each obvserve transaction on EVM chains. The function iterates through **each log** emitted by the transaction, and determines if any valid logs were emitted by the **THORChain router**.

If it determines that a log was emitted by the `THORChain` router, it **parses that log** and **forwards** the appropriate details to the THORChain Layer 1 for processing. **This is an incredibly sensitive and crucial piece of the codebase**, as if it can be tricked, this means malicious contracts can trick Bifrost into informing THORChain of something that didn’t actually happen, leading to loss of funds. In fact, in July of 2021, THORChain’s old router + Bifrost were hacked in this exact way.

"

However, considering protocol integrates with tokens whose balances change outside transfers, this would mean that where as the `GetTxInItem` would assume a transfer that was made for any of these tokens and emmiited to be a valid transaction, there is a high chance that by the time the transaction is to be executed on the Layer 1 for processing, these balances would have changed.

This would then allow for an attacker to easily game the protocol in a way, for example the LIDO stETH token normally rebases around 12pm, so an attacker can always watch the mempool on the rebase from LIDO around the time and in the case where the rebase is going to skim off or heavily increase the balances they can position themselves to make the most out of the transaction by frontrunning the rebase update with a transfer in the `THORChain` router, and by the time this log is verified by `GetTxInItem` to be processed on the layer 1 chain the balance would have already chan
In _transferOutAndCallV5, ETH is incorrectly sent to target
Audit: 2024-06-thorchain-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-thorchain/blob/e3fd3c75ff994dce50d6eb66eb290d467bd494f5/chain/ethereum/contracts/THORChain_Router.sol#L324


# Vulnerability details

## Impact
In the _transferOutAndCallV5 function, the original intention is to send ETH directly to the recipient if the swap is unsuccessful. This is stated in the [comments](https://github.com/code-423n4/2024-06-thorchain/blob/e3fd3c75ff994dce50d6eb66eb290d467bd494f5/chain/ethereum/contracts/THORChain_Router.sol#L324C82-L324C135). However, the code incorrectly sends ETH to the target, and then the TransferOutAndCallV5 event is triggered to indicate successful execution. This will cause users to lose funds.

## Proof of Concept
First, perform the exchange in the _transferOutAndCallV5 function:
```solidity
  function _transferOutAndCallV5(
    TransferOutAndCallData calldata aggregationPayload
  ) private {
    if (aggregationPayload.fromAsset == address(0)) {
      // call swapOutV5 with ether
      (bool swapOutSuccess, ) = aggregationPayload.target.call{
        value: msg.value
      }(
        abi.encodeWithSignature(
          "swapOutV5(address,uint256,address,address,uint256,bytes,string)",
          aggregationPayload.fromAsset,
          aggregationPayload.fromAmount,
          aggregationPayload.toAsset,
          aggregationPayload.recipient,
          aggregationPayload.amountOutMin,
          aggregationPayload.payload,
          aggregationPayload.originAddress
        )
      );
```
Then if it is unsuccessful, the ETH is sent to the target, which causes a loss of funds in the recipient:
```solidity
      if (!swapOutSuccess) {
        bool sendSuccess = payable(aggregationPayload.target).send(msg.value); // If can't swap, just send the recipient the gas asset
```

## Tools Used
manual

## Recommended Mitigation Steps
```diff
-       bool sendSuccess = payable(aggregationPayload.target).send(msg.value); // If can't swap, just send the recipient the gas asset
+       bool sendSuccess = payable(aggregationPayload.recipient).send(msg.value); // If can't swap, just send the recipient the gas asset
```


## Assessed type

Other
_transferOutAndCallV5 emits event even if aggregator fails
Audit: 2024-06-thorchain-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-thorchain/blob/e3fd3c75ff994dce50d6eb66eb290d467bd494f5/ethereum/contracts/THORChain_Router.sol#L362-L389


# Vulnerability details

## Impact

The `transferOutAndCall` function, when `aggregationPayload.fromAsset == address(0)` emits a `TransferOutAndCallV5` event regardless whether the swapOut was successfull or not. 

This broadcasts false information on-chain and could have severe consequences since THORChain uses broadcasted events as input.  

 
## Proof of Concept

In the `_transferOutAndCallV5` function, we can observe the following steps. 

1. The function attempts to perform a swapOut.
2. If this fails, it attempts to send the ETH directly to the sender.
3. If this fails, it sends the ETH back to the vault. 
  
```solidity
    if (aggregationPayload.fromAsset == address(0)) {
      // call swapOutV5 with ether
      (bool swapOutSuccess, ) = aggregationPayload.target.call{
        value: msg.value
      }(
        abi.encodeWithSignature(
          "swapOutV5(address,uint256,address,address,uint256,bytes,string)",
          aggregationPayload.fromAsset,
          aggregationPayload.fromAmount,
          aggregationPayload.toAsset,
          aggregationPayload.recipient,
          aggregationPayload.amountOutMin,
          aggregationPayload.payload,
          aggregationPayload.originAddress
        )
      );
      if (!swapOutSuccess) {
        bool sendSuccess = payable(aggregationPayload.target).send(msg.value); // If can't swap, just send the recipient the gas asset
        if (!sendSuccess) {
          payable(address(msg.sender)).transfer(msg.value); // For failure, bounce back to vault & continue.
        }
      }
```
However, just below this we find: 
```solidity
      emit TransferOutAndCallV5(
        msg.sender,
        aggregationPayload.target,
        msg.value,
        aggregationPayload.toAsset,
        aggregationPayload.recipient,
        aggregationPayload.amountOutMin,
        aggregationPayload.memo,
        aggregationPayload.payload,
        aggregationPayload.originAddress
      );
```
The event emission is not conditional on the success of any of the above steps. If the swap fails and sending ETH to the target fails as well, the function will still emit an event as if a swap has happened. 



## Tools Used

Manual Review

## Recommended Mitigation Steps

Include the event emission in the conditional for swap success. No success, no emission. 


## Assessed type

Other
Rebasing tokens are not handled correctly
Audit: 2024-06-thorchain-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-thorchain/blob/e3fd3c75ff994dce50d6eb66eb290d467bd494f5/chain/ethereum/contracts/THORChain_Router.sol#L54


# Vulnerability details

## Impact
Not handling rebasing tokens properly can result some vaults not being able to use their allowances due to lack of funds in the router or amount of rebasing tokens to get locked forever.

## Proof of Concept
Rebasing tokens like stETH for example can change the users underlying balance in both directions due to adding rewards or slashing.

In such case it is not correct to store the allowances for vaults in a storage variable while using the raw version of stETH because the underlying balance of the Router contract will change over time due to Lido's protocol logic.

So if stETH contract balance increases over time even if all `_vaultAllowance[vault][token]` go to 0 (due to transfer out functions usage), there will be remaining stETH amounts that will get locked in the contract forever.

On the other hand if a slashing event occurs and all vaults try to reduce their `_vaultAllowance[vault][token]` to 0, not all will be able to do it. The last couple of vaults will not be able to do this because there won't be enough stETH left in the router.

## Tools Used

Manual Review

## Recommended Mitigation Steps

Rebasing tokens should be handled differently from normal ERC20 tokens. One solution I think of is when accepting such tokens they should be wrapped to their non rebasing version. This way _vaultAllowance logic will not break. In the case of stETH, the tokens should be converted to wstETH.





## Assessed type

ERC20
[H-03] Incorrect event emissions, tricking the `smartcontract_log_parser`
Audit: 2024-06-thorchain-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-thorchain/blob/main/ethereum/contracts/THORChain_Router.sol#L330
https://github.com/code-423n4/2024-06-thorchain/blob/main/ethereum/contracts/THORChain_Router.sol#L330
https://github.com/code-423n4/2024-06-thorchain/blob/main/ethereum/contracts/THORChain_Router.sol#L231
https://github.com/code-423n4/2024-06-thorchain/blob/main/ethereum/contracts/THORChain_Router.sol#L206


# Vulnerability details

## Impact
The system must emit only correct events for the `smartcontract_log_parser` to process only valid actions.
In the `THORChain_Router::transferOut`, `THORChain_Router::_transferOutV5`, `THORChain_Router::transferOutAndCall` and `THORChain_Router::_transferOutAndCallV5` events are emitted even if the sending of the funds is not successful

`smartcontract_log_parser` will process incorrect events, leading to a protocol's loss of funds and this is very bad according to the documentation

## Proof of Concept
Please add a new test file called for example `7_Incorrect_Event_Emission.js` and paste the code from below.
The code asserts that an event is emitted even if the send has failed and the funds are refunded to the `msg.sender`

```javascript
const Router = artifacts.require('THORChain_Router');
const BigNumber = require('bignumber.js');
const { expect } = require('chai');
function BN2Str(BN) {
  return new BigNumber(BN).toFixed();
}

var ROUTER, ASGARD, USER1;

const ETH = '0x0000000000000000000000000000000000000000';
const _1 = '1000000000000000000';

describe('Incorrect emit of events', function () {
  let accounts;

  before(async function () {
    accounts = await web3.eth.getAccounts();
    ROUTER = await Router.new();
    USER1 = accounts[0];
    ASGARD = accounts[3];
  });

  it('Should emit emit on failed send', async function () {
    /* 
      Make a transfer call which will try to send the amount to the router,
      but will not be successful and return the ethers to the USER1 
    */
    const tx = await ROUTER.transferOut(ROUTER.address, ETH, _1, 'MEMO', {
      from: USER1,
      value: _1,
    });

    /* Get ending balances of */
    const endingBalanceOfUser1 = await web3.eth.getBalance(USER1);
    const endingBalanceOfRouter = await web3.eth.getBalance(ROUTER.address);

    /* Log ending balances */
    console.log('\nEnding Balance USER1:', BN2Str(endingBalanceOfUser1));
    console.log('Ending Balance ROUTER:', BN2Str(endingBalanceOfRouter));

    /* Assert that transfer out event was emitted even if the transfer failed */
    expect(tx.logs[0].event).to.equal('TransferOut');
    expect(tx.logs[0].args.to).to.equal(ROUTER.address);
    expect(tx.logs[0].args.asset).to.equal(ETH);
    expect(tx.logs[0].args.memo).to.equal('MEMO');
    expect(BN2Str(tx.logs[0].args.amount)).to.equal(_1);
    expect(BN2Str(endingBalanceOfRouter)).to.be.equal('0');
  });
});
```

## Tools Used
Manual Review

## Recommended Mitigation Steps
Emit events only if the actions are successful





#
Attacker can steal shares of "vault-like" tokens, such as stETH, that should belong to legitimate vaults
Audit: 2024-06-thorchain-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-thorchain/blob/5b91b5c6683a222b0ce046533515e301c9699d74/chain/ethereum/contracts/THORChain_Router.sol#L131-L140
https://github.com/code-423n4/2024-06-thorchain/blob/5b91b5c6683a222b0ce046533515e301c9699d74/chain/ethereum/contracts/THORChain_Router.sol#L143-L160
https://github.com/code-423n4/2024-06-thorchain/blob/5b91b5c6683a222b0ce046533515e301c9699d74/chain/ethereum/contracts/THORChain_Router.sol#L185-L207
https://github.com/code-423n4/2024-06-thorchain/blob/5b91b5c6683a222b0ce046533515e301c9699d74/chain/ethereum/contracts/THORChain_Router.sol#L209-L238


# Vulnerability details

## Impact
An attacker can call the following `depositWithExpiry` function with an address controlled by him as the `vault` input. After the `_deposit` function below is called, he has sent the `amount` tokens to the router, and `_vaultAllowance[vault][asset]` for his controlled address has increased by the `amount`. This is problematic when the `asset` is a "vault-like" token, such as stETH that needs to be supported by this protocol according to this protocol's [token whitelist](https://gitlab.com/thorchain/thornode/-/blob/develop/common/tokenlist/ethtokens/eth_mainnet_latest.json?ref_type=heads#L3074-3081).

https://github.com/code-423n4/2024-06-thorchain/blob/5b91b5c6683a222b0ce046533515e301c9699d74/chain/ethereum/contracts/THORChain_Router.sol#L131-L140
```solidity
  function depositWithExpiry(
    address payable vault,
    address asset,
    uint amount,
    string memory memo,
    uint expiration
  ) external payable {
    require(block.timestamp < expiration, "THORChain_Router: expired");
    _deposit(vault, asset, amount, memo);
  }
```

https://github.com/code-423n4/2024-06-thorchain/blob/5b91b5c6683a222b0ce046533515e301c9699d74/chain/ethereum/contracts/THORChain_Router.sol#L143-L160
```solidity
  function _deposit(
    address payable vault,
    address asset,
    uint amount,
    string memory memo
  ) private nonReentrant {
    uint safeAmount;
    if (asset == address(0)) {
      ...
    } else {
      require(msg.value == 0, "unexpected eth"); // protect user from accidentally locking up eth
      safeAmount = safeTransferFrom(asset, amount); // Transfer asset
      _vaultAllowance[vault][asset] += safeAmount; // Credit to chosen vault
    }
    ...
  }
```

As shown by the `StETH` contract's functions below, calling the `StETH.transferFrom` function, which eventually calls the `StETH.getSharesByPooledEth` function, updates the stETH holders' shares instead of updating their balances directly. The stETH holders' `shares` are stored in the `StETH` contract, and according to the `StETH.balanceOf` function, their stETH balances corresponding to their `shares` are dynamic depending on the total pooled Ether and total shares for the `StETH` contract. After the attacker's `depositWithExpiry` function call, the router's `shares` is increased by a share amount that corresponds to the `amount` stETH tokens ba
THORChain_Router:TransferOut event will be emitted even it the ETH transfer wasn't successful 
Audit: 2024-06-thorchain-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-thorchain/blob/e3fd3c75ff994dce50d6eb66eb290d467bd494f5/chain/ethereum/contracts/THORChain_Router.sol#L185


# Vulnerability details

## Impact & Proof of concept
The code in transferOut() function first checks if it is Eth transfer it tries to send it to the target, if not successful it will transfer Eth back to the vault.
No matter what the choice was, the event eventually will be emitted the same way.
 
```solidity
    emit TransferOut(msg.sender, to, asset, safeAmount, memo);
```
 this will mislead the smartcontract_log_parser into thinking that a transfer was successful when it wasn't.



## Tools Used
manual review

## Recommended Mitigation Steps
Add one more parameter in transferOut event to indicate wether the transfer succeeded or not.

```solidity 
- event TransferOut(
    address indexed vault,
    address indexed to,
    address asset,
    uint amount,
    string memo
  );
+ event TransferOut(
    address indexed vault,
    address indexed to,
    address asset,
    uint amount,
    string memo,
    bool success
  );
```
NOTE: The same issue  exists in:
- _transferOutV5()
- transferOutAndCall()
- _transferOutAndCallV5()






## Assessed type

Other
Events arent being logged and parsed properly according to the docs.
Audit: 2024-06-thorchain-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-thorchain/blob/e3fd3c75ff994dce50d6eb66eb290d467bd494f5/chain/ethereum/contracts/THORChain_Router.sol#L209
https://github.com/code-423n4/2024-06-thorchain/blob/e3fd3c75ff994dce50d6eb66eb290d467bd494f5/chain/ethereum/contracts/THORChain_Router.sol#L247
https://github.com/code-423n4/2024-06-thorchain/blob/e3fd3c75ff994dce50d6eb66eb290d467bd494f5/chain/ethereum/contracts/THORChain_Router.sol#L466
https://github.com/code-423n4/2024-06-thorchain/blob/e3fd3c75ff994dce50d6eb66eb290d467bd494f5/chain/ethereum/contracts/THORChain_Router.sol#L176


# Vulnerability details

## Impact
There are 2 issues
- As there are no events of any V5 based functions that are being parsed in [smartcontract_log_parser.go](https://github.com/code-423n4/2024-06-thorchain/blob/main/bifrost/pkg/chainclients/shared/evm/smartcontract_log_parser.go) due to which all of the v5 function based txn will be considered invalid.
- This issue also lies in the [_routerDeposit](https://github.com/code-423n4/2024-06-thorchain/blob/e3fd3c75ff994dce50d6eb66eb290d467bd494f5/chain/ethereum/contracts/THORChain_Router.sol#L466) which also doesn't emit any event due to which [transferAllowance](https://github.com/code-423n4/2024-06-thorchain/blob/e3fd3c75ff994dce50d6eb66eb290d467bd494f5/chain/ethereum/contracts/THORChain_Router.sol#L176) txn would be considered valid if the router is different.
>In the discord server it was mentioned that any V5 functionality that isn't in `smartcontract_log_parser` should be considered out of scope, even in this case the second impact stands true and it seems to be huge to consider this finding a medium severity one.
## Proof of Concept
In the [readme](https://github.com/code-423n4/2024-06-thorchain#main-invariants) one of the core invariants is:
> Only valid events emitted from the Router contract itself should result in the txInItem parameter being populated in the GetTxInItem function of the smartcontract_log_parser

The current implementation seems to completely break this invariant not only for V5 functions but also for [_routerDeposit](https://github.com/code-423n4/2024-06-thorchain/blob/e3fd3c75ff994dce50d6eb66eb290d467bd494f5/chain/ethereum/contracts/THORChain_Router.sol#L466)

## Tools Used
Manual review
## Recommended Mitigation Steps
- Make sure to emit an event in `_routerDeposit`
- Update the smartcontract_log_parser.go according to the event of V5 functions






## Assessed type

Other