Farseen0/scar-pairs huggingface dataset:
LOW severity: TRST-Governance-related risks. **Description:** 

There are several ways in which a malicious or hacked governance can take user funds. Through the WalletAdapterRegistry, governance can register new wallet adapters arbitrarily. A malicious adapter can be abused easily as it can transform an incoming benign transaction to a...

Vulnerable code:
function _executeOnWallet(address _wallet, Types.Executable memory_txn) 
        internal returns (bytes memory) {
          if (isEmergencyPaused) revert EmergencyPaused();
    // Get wallet adapter for the wallet
        IWalletAdapter adapter = findWalletAdapter(_wallet);
    // Format transaction into a BrahRouter compatible executable
          Types.Executable memory formattedTxn = adapter.formatForWallet(_wallet, _txn);
    // Execute transaction
          (bool success, bytes memory result) = _execute(formattedTxn);
    // Check if transaction was successful and return data require(success, string(abi.encodePacked("brahRouter call fail",
      result)));
    (bool txnSuccess, bytes memory txnResult) = adapter.decodeReturnData(result);
        require(txnSuccess, string(abi.encodePacked("wallet call fail", txnResult)));
      return (txnResult);
    }

function executeTrustedAutomation( address _wallet, 
      address _subAccount, address _strategy,
  Types.Executable[] memory _actionExecs)
           external claimExecutionFees(_wallet) { Authorizer._validateConsoleKeeper(); Authorizer._validateTrustedSubscription(_subAccount, _strategy);
        Executor._executeAutomation(_wallet, _subAccount, _strategy,_actionExecs);
     emit TrustedExecution(_subAccount, _strategy);
    }

function _executeOnSubAccount(address _owner, address _subAccount,
    address strategy, Types.Executable memory _txn)
  internal
    returns (bytes memory)
  {
  if (!IStrategy(strategy).isExecutionAllowed(_txn.callType,
       _txn.target, _subAccount)) revert StrategyBlocked();
HIGH severity: TRST-Attacker can freeze deposits and withdrawals indefinitely by submitting a bad withdrawal. **Description:**
Users request to queue a withdrawal using the function below in Vault.

Notice that the function only validates that the user has a sufficient LP token balance to 
withdraw at the moment of execution. After it is queued up, a user can move their tokens to 
another wallet. Later in.....

Vulnerable code:
function addWithdrawRequest(uint256 _amountMLP, address _token) external {
            require(isAcceptingToken(_token), "ERROR: Invalid token");
                require(_amountMLP != 0, "ERROR: Invalid amount");
        
        address _withdrawer = msg.sender;
        // Get the pending buffer and staged buffer.
             RequestBuffer storage _pendingBuffer = _requests(false);
             RequestBuffer storage _stagedBuffer = _requests(true);
        // Check if the withdrawer have enough balance to withdraw.
        uint256 _bookedAmountMLP =  _stagedBuffer.withdrawAmountPerUser[_withdrawer] + 
       _pendingBuffer.withdrawAmountPerUser[_withdrawer];
            require(_bookedAmountMLP + _amountMLP <= 
                MozaicLP(mozLP).balanceOf(_withdrawer), "Withdraw amount > amount  MLP");
        …
        emit WithdrawRequestAdded(_withdrawer, _token, chainId, _amountMLP);
        }

// Burn moazic LP token.
            MozaicLP(mozLP).burn(request.user, _mlpToBurn);
MEDIUM severity: TRST-Removal of Multisig members will corrupt data structures. **Description:**
The Mozaic Multisig (the senate) can remove council members using the **TYPE_DEL_OWNER**
operation:

The code finds the owner's index in the councilMembers array, copies all subsequent 
members downwards, and deletes the last element. Finally, it deletes the...

Vulnerable code:
if(proposals[_proposalId].actionType == TYPE_DEL_OWNER) {
                (address _owner) = abi.decode(proposals[_proposalId].payload, (address));
        require(contains(_owner) != 0, "Invalid owner address");
            uint index = contains(_owner);
                for (uint256 i = index; i < councilMembers.length - 1; i++) {
            councilMembers[i] = councilMembers[i + 1];
        }
            councilMembers.pop();
                 proposals[_proposalId].executed = true;
                     isCouncil[_owner] = false;
          }

function contains(address _owner) public view returns (uint) {
              for (uint i = 1; i <= councilMembers.length; i++) {
        if (councilMembers[i - 1] == _owner) {
                 return i;
             }
         }
         return 0;
         }
MEDIUM severity: TRST-Attacker could abuse victim's vote to pass their own proposal. **Description:**
Proposals are created using `submitProposal()`:

After submission, council members approve them by calling `confirmTransaction()`:

Notably, the **_proposalId** passed to `confirmTransaction()` is simply the **proposalCount** at time 
of submission. This design allows the...

Vulnerable code:
function submitProposal(uint8 _actionType, bytes memory _payload)  public onlyCouncil {
             uint256 proposalId = proposalCount;
                 proposals[proposalId] = Proposal(msg.sender,_actionType, 
                    _payload, 0, false);
                proposalCount += 1;
         emit ProposalSubmitted(proposalId, msg.sender);
        }

function confirmTransaction(uint256 _proposalId) public onlyCouncil 
            notConfirmed(_proposalId) {
             confirmations[_proposalId][msg.sender] = true;
             proposals[_proposalId].confirmation += 1;
        emit Confirmation(_proposalId, msg.sender);
        }
MEDIUM severity: TRST-Users can lose their entire xMoz balance when specifying too short a duration for redemption. **Description:**
Users can convert their XMoz to Moz through MozStaking, using `redeem()`.

If the specified duration is shorter than the minRedeemDuration specified in the staking 
contract, **mozAmount** will end up being zero. In such scenarios, redeem will consume user's 
**xMozAmount**...

Vulnerable code:
function redeem(uint256 xMozAmount, uint256 duration) external {
                require(xMozAmount > 0, "redeem: xMozAmount cannot be zero");
                    xMozToken.transferFrom(msg.sender, address(this), xMozAmount);
                    uint256 redeemingAmount = xMozBalances[msg.sender];
                   // get corresponding MOZ amount
                    uint256 mozAmount = getMozByVestingDuration(xMozAmount, duration);
                 if (mozAmount > 0) {
             emit Redeem(msg.sender, xMozAmount, mozAmount, duration);
            // add to total
             xMozBalances[msg.sender] = redeemingAmount + xMozAmount;
             // add redeeming entry
                userRedeems[msg.sender].push(RedeemInfo(mozAmount, 
             xMozAmount, _currentBlockTimestamp() + duration));
             }
              }
MEDIUM severity: TRST-MozToken will have a much larger fixed supply than intended.. **Description:** 
MozToken is planned to be deployed on all supported chains. Its total supply will be 1B. 
However, its constructor will mint 1B tokens on each deployment.

**Recommended Mitigation:**
Pass the minted supply as a parameter. Only on the main chain, mint 1B tokens.

**Team...

Vulnerable code:
constructor( address _layerZeroEndpoint, uint8 _sharedDecimals
            ) OFTV2("Mozaic Token", "MOZ", _sharedDecimals, _layerZeroEndpoint) {
            _mint(msg.sender, 1000000000 * 10 ** _sharedDecimals);
                isAdmin[msg.sender] = true;
            }
MEDIUM severity: TRST-MozToken allows owner to mint an arbitrary amount of tokens, although supply is fixed. **Description:**
Supply of MozToken is defined to be fixed at 1B tokens:
**Max Supply**
1B MOZ will be minted at the genesis and will be the entire finite supply of tokens

However, there is an exposed `mint()` function which allows the owner to mint arbitrary 
amount of tokens.

This would...

Vulnerable code:
function mint(address to, uint256 amount) public onlyOwner {
            _mint(to, amount);
            }

function mint(uint256 _amount, address _to) external   onlyStakingContract {
            _mint(_to, _amount);
           }

function setStakingContract(address _mozStaking) external onlyOwner {
              require(_mozStaking != address(0x0), "Invalid address");
             mozStaking = _mozStaking;
            }
HIGH severity: TRST-The vault cannot operate with popular non-conforming ERtokens due to unsafe transfers. **Description:**
In Vault, the admin can deposit and withdraw tokens using the functions below:

However, it uses `transfer()`/`transferFrom()` directly, instead of using a safe transfer library. 
There are hundreds of tokens who do not use the standard ERC20 signature and return void. 
Such...

Vulnerable code:
///@notice Withdraw token with specified amount.
        function withdrawToken(address _token, uint256 _amount) external onlyAdmin {
             require(_amount != 0, "ERROR: Invalid amount");
                uint256 _curAmount = IERC20(_token).balanceOf(address(this));
                    require(_curAmount >= _amount, "ERROR: Current balance is too low");
        IERC20(_token).transfer(msg.sender, _amount);
        }
        ///@notice Deposit token with specified amount.
        function depositToken(address _token, uint256 _amount) external onlyAdmin {
                require(isAcceptingToken(_token), "ERROR: Invalid token");
                    require(_amount != 0, "ERROR: Invalid amount");
                        IERC20(_token).transferFrom(msg.sender, address(this), _amount);
        }

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
MEDIUM severity: TRST-Vault does not have a way to withdraw native tokens. **Description:**
The Vault sets the LayerZero fee refund address to itself:

However, there is no function to withdraw those funds, making them forever stuck in the vault 
only available for paying for future transactions.

**Recommended mitigation:**
Add a native token withdrawal...

Vulnerable code:
/// @notice Report snapshot of the vault to the controller.
        function reportSnapshot() public onlyBridge {
                 MozBridge.Snapshot memory _snapshot = _takeSnapshot();
             MozBridge(mozBridge).reportSnapshot(_snapshot, 
          payable(address(this)));
        }

function withdraw() public {
        // get the amount of Ether stored in this contract
            uint amount = address(this).balance;
        // send all Ether to owner
        // Owner can receive Ether since the address of owner is payable
            (bool success, ) = treasury.call{value: amount}("");
                 require(success, "Controller: Failed to send Ether");
         }
MEDIUM severity: TRST-MozBridge underestimates gas for sending of Moz messages. **Description:**
The bridge calculates LayerZero fees for sending Mozaic messages using the function below:

The issue is that the actual payload used for Mozaic messages is longer than the one calculated 
above. For example, REPORT_SNAPSHOT messages include a **Snapshot** structure.
...

Vulnerable code:
function quoteLayerZeroFee(uint16 _chainId, uint16 _msgType, LzTxObj memory _lzTxParams) public view returns (uint256 _nativeFee, uint256 _zroFee) { 
             bytes memory payload = "";
        if (_msgType == TYPE_REPORT_SNAPSHOT) {
                payload = abi.encode(TYPE_REPORT_SNAPSHOT);
        }
        else if (_msgType == TYPE_REQUEST_SNAPSHOT) {
                     payload = abi.encode(TYPE_REQUEST_SNAPSHOT);
        }
        else if (_msgType == TYPE_SWAP_REMOTE) {
                        payload = abi.encode(TYPE_SWAP_REMOTE);
        }
        else if (_msgType == TYPE_STAKE_ASSETS) {
                          payload = abi.encode(TYPE_STAKE_ASSETS);
        }   
        else if (_msgType == TYPE_UNSTAKE_ASSETS) {
                                 payload = abi.encode(TYPE_UNSTAKE_ASSETS);
        }
        else if (_msgType == TYPE_REPORT_SETTLE) {
                                 payload = abi.encode(TYPE_REPORT_SETTLE);
        }
        else if (_msgType == TYPE_REQUEST_SETTLE) {
                            payload = abi.encode(TYPE_REQUEST_SETTLE);
        }
        else {
                         revert("MozBridge: unsupported function type");
        }
        
                     bytes memory _adapterParams = _txParamBuilder(_chainId, _msgType, _lzTxParams);
              return layerZeroEndpoint.estimateFees(_chainId, address(this), 
       payload, useLayerZeroToken, _adapterParams);
        }

struct Snapshot {
               uint256 depositRequestAmount;
                 uint256 withdrawRequestAmountMLP;
                     uint256 totalStablecoin;
                         uint256 totalMozaicLp; // Mozaic "LP"
                             uint8[] pluginIds;
                                 address[] rewardTokens;
                                  uint256[] amounts;
                   }
MEDIUM severity: TRST-No slippage protection for cross-chain swaps in StargatePlugin. **Description:**
The StargatePlugin calls StargateRouter's swap() function to do a cross-chain swap.
 
It will pass 0 as the minimum amount of tokens to receive. This pattern is vulnerable to 
sandwich attacks, where the fee or conversion rate is pumped to make the user receive hardly 
any tokens......

Vulnerable code:
// Swaps
            IStargateRouter(_router).swap(_dstChainId, _srcPoolId, _dstPoolId, 
                  payable(address(this)), _amountLD, 0, IStargateRouter.lzTxObj(0, 0, "0x"), abi.encodePacked(_to), bytes(""));
LOW severity: TRST-Theoretical reentrancy attack when TYPE_MINT_BURN proposals are executed. **Description:**
The senate can pass a proposal to mint or burn tokens.
 

Note that the proposal is only marked as executed at the end of execution, but execution is 
checked at the start of the function.

Interaction with tokens should generally be assumed to grant arbitrary call execution to...

Vulnerable code:
if(proposals[_proposalId].actionType == TYPE_MINT_BURN) {
            (address _token, address _to, uint256 _amount, bool _flag) = 
                abi.decode(proposals[_proposalId].payload, (address, address, uint256, bool));
        if(_flag) {
            IXMozToken(_token).mint(_amount, _to);
        } else {
                     IXMozToken(_token).burn(_amount, _to);
        }
        proposals[_proposalId].executed = true;
        }

function execute(uint256 _proposalId) public onlyCouncil {
                 require(proposals[_proposalId].executed == false, "Error: 
            Proposal already executed.");
        require(proposals[_proposalId].confirmation >= threshold, "Error: Not enough confirmations.");
LOW severity: TRST-XMozToken permits transfers from non-whitelisted addresses. **Description:**
The XMozToken is documented to forbid transfers except from whitelisted addresses or mints.

However, as can be seen, non-whitelisted users can still transfer tokens, so long as it is to 
whitelisted destinations. 

**Recommended Mitigation:**
Remove the additional check in...

Vulnerable code:
/**
        * @dev Hook override to forbid transfers except from whitelisted 
        addresses and minting
        */
        function _beforeTokenTransfer(address from, address to, uint256 
        /*amount*/) internal view override {
                require(from == address(0) || _transferWhitelist.contains(from) 
                  || _transferWhitelist.contains(to), "transfer: not allowed");
                 }

function _beforeTokenTransfer(address from, address to, uint256 
        /*amount*/) internal view override {
              require(from == address(0) || to == address(0) || from == owner() 
                 || isTransferWhitelisted(from), "transfer: not allowed");
             }
LOW severity: TRST-XMozToken cannot be added to its own whitelist. **Description:**
By design, XMozToken should always be in the whitelist. However, `updateTransferWhitelist()`
implementation forbids both removal and insertion of XMozToken to the whitelist.

**Recommended Mitigation:**
Move the **require** statement into the **else** clause.

**Team...

Vulnerable code:
function updateTransferWhitelist(address account, bool add) external  onlyMultiSigAdmin {
                    require(account != address(this), "updateTransferWhitelist: 
                          Cannot remove xMoz from whitelist");
                    if(add) _transferWhitelist.add(account);
                 else _transferWhitelist.remove(account);
            emit SetTransferWhitelist(account, add);
            }
LOW severity: TRST-Vault will fail to operate plugins with USDT due to lack of zero approval. **Description:**
Admins can trigger the execute() function to interact with plugins.

Some tokens like USDT will revert when calling `approve()` when the previous allowance is not 
zero (to protect against a well-known double-allowance attack). Therefore, if the plugin does 
not consume the entire.....

Vulnerable code:
if(_actionType == IPlugin.ActionType.Stake) {
                 (uint256 _amountLD, address _token) = abi.decode(_payload, (uint256, address));
        IERC20(_token).approve(supportedPlugins[_pluginId].pluginAddr, _amountLD);
                } else if(_actionType == IPlugin.ActionType.SwapRemote) {
                     (uint256 _amountLD, address _token, , ) = abi.decode(_payload, 
                         (uint256, address, uint16, uint256));
                 IERC20(_token).approve(supportedPlugins[_pluginId].pluginAddr, 
        _amountLD);
        }
        IPlugin(supportedPlugins[_pluginId].pluginAddr).execute(_actionType, 
        _payload);
LOW severity: TRST-Controller doesn't initialize supported chains properly. **Description:** 
Controller manages a list of **supportedChainIds** where the protocol is deployed. The 
**mainChainId** is the base chain where controller is deployed. For settling and snapshotting, 
there is different handing in case the current chainID is **mainChainId**:

In fact, the...

Vulnerable code:
if(mainChainId == supportedChainIds[i]) {
                   MozBridge.Snapshot memory _snapshot = mozBridge.takeSnapshot();
             _updateSnapshot(mainChainId, _snapshot);
                         } else {
                    mozBridge.requestSnapshot(supportedChainIds[i], payable(master));
                }
LOW severity: TRST-Admin can set plugin fee to 100%. **Description:** 
The admin can set Mozaic's cut from strategy earnings through setFee(), up to 100%.

Vulnerable code:
function setFee(uint256 _mozaicFeeBP, uint256 _treasuryFeeBP)  external onlyOwner {
             require(_mozaicFeeBP <= BP_DENOMINATOR, "Stargate: fees > 100%");
                require(_treasuryFeeBP <= BP_DENOMINATOR, "Stargate: fees > 100%");
            mozaicFeeBP = _mozaicFeeBP;
        treasuryFeeBP = _treasuryFeeBP;
HIGH severity: Cache invariants. In some parts of the codebase, external calls are used to get values at every invocation 
although they are not expected to ever change. For example, the `convertLDtoMD()` function:

The token's `decimals()` are fixed. Consider caching them for improved performance.

Vulnerable code:
function convertLDtoMD(address _token, uint256 _amountLD) public view returns (uint256) {
                    uint8 _localDecimals = IERC20Metadata(_token).decimals();
                        if (MOZAIC_DECIMALS >= _localDecimals) {
                    return _amountLD * (10**(MOZAIC_DECIMALS - _localDecimals));
             } else {
        return _amountLD / (10**(_localDecimals - MOZAIC_DECIMALS));
                 }
         }
HIGH severity: TRST-A malicious operator can drain the vault funds in one transaction. **Description:**
The vault operator can swap tokens using the `trade()` function. They pass the following 
structure for each trade:

Notably, **receiveAmtMin** is used to guarantee acceptable slippage. An operator can simply 
pass 0 to make sure the trade is executed. This allows an operator to...

Vulnerable code:
struct tradeInput { 
             address spendToken;
               address receiveToken;
                 uint256 spendAmt;
                   uint256 receiveAmtMin;
                address routerAddress;
         uint256 pathIndex;
         }

(,int priceFromInt,,,) = AIFrom.latestRoundData();
         (,int priceToInt,,,) = AITo.latestRoundData();
HIGH severity: TRST-A malicious operator can steal all user deposits. **Description:**
In the Orbital architecture, each Vault user has a numerator which represents their share of 
the vault holdings. The denominator is by design the sum of all numerators of users, an 
invariant kept at deposits and withdrawals. For maximum precision, the denominator should 
be a...

Vulnerable code:
if (D == 0) { //initial deposit
                   uint256 sumDenoms = 0; 
                        for (uint256 i = 0; i < tkns.length; i++) {
                              sumDenoms += 
                        AI.getAllowedTokenInfo(tkns[i]).initialDenominator;
                      }
                   require(sumDenoms > 0 && sumDenoms <= maxInitialDenominator, 
         "invalid sumDenoms");
                   deltaN = sumDenoms; //initial numerator and denominator are the 
                same, and are greater than any possible balance in the vault.
             //this ensures precision in the vault's 
         balances. User Balance = (N*T)/D will have rounding errors always 1 
         wei or less. 
         } else { 
            // deltaN = (amt * D)/T;
            deltaN = Arithmetic.overflowResistantFraction(amt, D, T);
         }
MEDIUM severity: TRST-Removing a trade path in router will cause serious data corruption. **Description:**
The RouterInfo represents a single UniV3-compatible router which supports a list of token 
paths. It uses the following data structures:

When an admin specifies a new path from **token0** to **token1**, `_increasePairPaths()` is called. 

When a path is removed, the complementary.....

Vulnerable code:
mapping(address => mapping(address => listInfo)) private allowedPairsMap;
                  pair[] private allowedPairsList;

struct listInfo {
               bool allowed;
                uint256 listPosition;
         }
         struct pair {
            address token0;
               address token1;
                  uint256 numPathsAllowed;
          }

function _increasePairPaths(address token0, address token1) private {
                     listInfo storage LI = allowedPairsMap[token0][token1];
                  if (!LI.allowed){
                  LI.allowed = true;
                  LI.listPosition = allowedPairsList.length;
                      allowedPairsList.push(pair(token0, token1, 0));
                   }
                      allowedPairsList[LI.listPosition].numPathsAllowed++;
                   }
MEDIUM severity: TRST-Attacker can DOS deposit transactions due to strict verifications. **Description:**
When users deposit funds to the Vault, it verifies that the proportion between the tokens 
inserted to the vault matches the current vault token balances.

The essential part of the check is below:

The exact logic here is not important, but note that a small change in the balance.....

Vulnerable code:
uint256[] memory balances = vlt.balances();
          //ensure deposits are in the same ratios as the vault's current balances
          require(functions.ratiosMatch(balances, amts), "ratios don't match");

for (uint256 i = 0; i < sourceRatios.length; i++) {
         // if (targetRatios[i] != (targetRatios[greatestIndex] * 
                  sourceRatios[i]) / greatest) {
               if (targetRatios[i] != 
         Arithmetic.overflowResistantFraction(targetRatios[greatestIndex], sourceRatios[i], greatest)) {
         return false;
            }
         }