HIGH severity: Qubit Finance — Insufficient validation. `safeTransferFrom()` in SafeToken.sol does not revert when the token EOA. tokenAddress can be address(0) to pass all check to mint xETH.. **safeTransferFrom() in SafeToken.sol** does not revert when the token EOA. 
tokenAddress can be address(0) to pass all check to mint xETH.

Vulnerable code:
function deposit(uint8 destinationDomainID, bytes32 resourceID, bytes calldata data) external payable notPaused {
    require(msg.value == fee, "QBridge: invalid fee");

    address handler = resourceIDToHandlerAddress[resourceID];
    require(handler != address(0), "QBridge: invalid resourceID");

    uint64 depositNonce = ++_depositCounts[destinationDomainID];

    IQBridgeHandler(handler).deposit(resourceID, msg.sender, data);
    emit Deposit(destinationDomainID, resourceID, depositNonce, msg.sender, data);
}

QBridgeHandler
function deposit(bytes32 resourceID, address depositer, bytes calldata data) external override onlyBridge {
    uint option;
    uint amount;
    (option, amount) = abi.decode(data, (uint, uint));

    address tokenAddress = resourceIDToTokenContractAddress[resourceID]; //without any tokenAddress check
    require(contractWhitelist[tokenAddress], "provided tokenAddress is not whitelisted");

    if (burnList[tokenAddress]) {
        require(amount >= withdrawalFees[resourceID], "less than withdrawal fee");
        QBridgeToken(tokenAddress).burnFrom(depositer, amount);
    } else {
        require(amount >= minAmounts[resourceID][option], "less than minimum amount");
        tokenAddress.safeTransferFrom(depositer, address(this), amount);  //vulnerable point
    }
}

/*
"input":{
"token":"0x0000000000000000000000000000000000000000"
"from":"0xd01ae1a708614948b2b5e0b7ab5be6afa01325c7"
"to":"0x17b7163cf1dbd286e262ddc68b553d899b93f526"
"value":"190000000000000000000"
}
*/
SafeToken.sol
function safeTransferFrom(
        address token,
        address from,
        address to,
        uint value
    ) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "!safeTransferFrom");
    } ... function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
    callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}

function callOptionalReturn(IERC20 token, bytes memory data) private {
    // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
    // we're implementing it ourselves.

    // A Solidity high level call has three parts:
    //  1. The target address is checked to verify it contains contract code
    //  2. The call itself is made, and success asserted
    //  3. The return value is decoded, which in turn checks the size of the returned data.
    // solhint-disable-next-line max-line-length
    require(Utils.isContract(address(token)), "SafeERC20: call to non-contract");

    // solhint-disable-next-line avoid-low-level-calls
    (bool success, bytes memory returndata) = address(token).call(data);
    require(success, "SafeERC20: low-level call failed");

    if (returndata.length > 0) { // Return data is optional
        // solhint-disable-next-line max-line-length
        require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }
}

Vulnerability type: Bridge, CrossChain, Insufficient validation, lending