if the Virtual Account's owner is a Contract Account (multisig wallet), attackers can gain control of the Virtual Accounts by gaining control of the same owner's address in a different chain
Audit: 2023-09-maia-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-maia/blob/main/src/RootPort.sol#L350-L353


# Vulnerability details

## Impact
- Attackers can gain control of User's Virtual Accounts and steal all the assets these accounts hold in the Root environment

## Proof of Concept
- When sending signed messages from a Branch to Root, the RootBridgeAgent contract calls the [`RootPort::fetchVirtualAccount()`](https://github.com/code-423n4/2023-09-maia/blob/main/src/RootPort.sol#L350-L353) to get the virtual account that is assigned in the Root environment to the address who initiated the call in the SrcBranch, and if that address doesn't have assigned a virtual account yet, it proceeds to create one and assign it.
- The problem is that the fetchVirtualAccount() function solely relies on the address of the caller in the SrcBranch, but it doesn't take into account from which Branch the call comes.

> BranchBridgeAgent.sol
```solidity
function callOutSignedAndBridge(
    ...
) external payable override lock {
  ...
  //Encode Data for cross-chain call.
  bytes memory payload = abi.encodePacked(
      _hasFallbackToggled ? bytes1(0x85) : bytes1(0x05),
      //@audit-info => Encodes the address of the caller in the Branch and sends it to the RootBridgeAgent
      //@audit-info => This address will be used to fetch the VirtualAccount assigned to it!
      msg.sender,
      _depositNonce,
      _dParams.hToken,
      _dParams.token,
      _dParams.amount,
      _dParams.deposit,
      _params
  );
}
```

> RootBridgeAgent.sol
```solidity
function lzReceiveNonBlocking(
  ...

) public override requiresEndpoint(_endpoint, _srcChainId, _srcAddress) {
  ...
  ...
  ...
  else if (_payload[0] == 0x04) {
      // Parse deposit nonce
      nonce = uint32(bytes4(_payload[PARAMS_START_SIGNED:PARAMS_TKN_START_SIGNED]));

      //Check if tx has already been executed
      if (executionState[_srcChainId][nonce] != STATUS_READY) {
          revert AlreadyExecutedTransaction();
      }

      //@audit-info => Reads the address of the msg.sender in the BranchBridgeAgent and forwards that address to the RootPort::fetchVirtualAccount()
      // Get User Virtual Account
      VirtualAccount userAccount = IPort(localPortAddress).fetchVirtualAccount(
          address(uint160(bytes20(_payload[PARAMS_START:PARAMS_START_SIGNED])))
      );

      // Toggle Router Virtual Account use for tx execution
      IPort(localPortAddress).toggleVirtualAccountApproved(userAccount, localRouterAddress);

    ...
    ...
  }
  ...
  ...
}

```
> RootPort.sol
```solidity
//@audit-info => Receives from the RootBridgeAgent contract the address of the caller in the BranchBridgeAgent contract
//@audit-info => Fetches the VirtualAccount assigned to the _user address regardless from what Branch the call came from
function fetchVirtualAccount(address _user) external override returns (VirtualAccount account) {
    account = getUserAccount[_user];
    if (address(account) == address(0)) account = addV