Skip to content
$1,000,000 in security audit grants are live now, Apply here →

Security review · August 2025

M Portal Lite

for M0

M0 engaged Guardian to review the security of their M0 M-Portal-Lite. From the 11th of August to the 12th of August, a team of 4 auditors reviewed the source code in scope.

Published
Review window
August 11 to 12, 2025
Language
Solidity
Chains
Ethereum, Arbitrum, Optimism, Linea
Sector
Stablecoins
  • 0 Critical
  • 0 High
  • 1 Medium
  • 1 Low
  • 2 Informational

4 acknowledged

Scope

Overview

M0 engaged Guardian to review the security of their M0 M-Portal-Lite. From the 11th of August to the 12th of August, a team of 4 auditors reviewed the source code in scope.

Findings 4

  1. M-01 Medium Happy Path: Normal Users Would Receive M Tokens Logical Error Acknowledged
    Location
    Portal.sol: 312-313

    Description

    The original intent for the M token was to be permissionless, allowing anyone to hold it. However, based on recent discussions with the M0 team, the model has changed:

    • New intent: Only selected role holders are allowed to handle the native M token directly.
    • Regular users should instead interact with M extensions (wrapped versions of M) for DeFi and other use

    cases.

    However, the current Portal implementation does not reflect this new intent. If the destination token in a spoke/hub transfer is set to the native M token address, the Portal will issue or transfer native M tokens directly.

    • The swapInM function in the Swap Facility only allows approved swappers to swap native M into wrapped

    M.

    • This means users who receive native M cannot wrap it themselves.
    • Since wrapped M is the expected token for DeFi integrations, users would be stuck holding the native token,

    unable to use it in the intended ecosystem.

    Under M0’s original (permissionless) deployment assumptions, this flow was fine. But with the new restricted model, this scenario can occur even in the happy path.

    Example:

    • On Mainnet Hub (0x36f586A30502AE3afb555b8aA4dCc05d233c2ecE), the destination token for Linea is

    currently set to native M.

    • As a result, if a user calls transfer on the Portal, they receive native M on Linea instead of the wrapped

    version.

    Recommendation

    Set the default destination token to the wrapped M (wM) instead of native M, so that by default:

    • The Portal wraps into wM before delivering to the user.
    • If a different extension specified, wrap into that instead.

    Resolution

    M0 Team: Acknowledged. This is acceptable behavior and will be addresses by configuration of approved bridging paths for Portals.

  2. L-01 Low Error Path : Normal User May Receive M Tokens Validation Acknowledged
    Location
    Portal.sol: 339-345

    Description

    When a user makes a cross chain transfer with a M extension token the flow looks like this:

    • On the source chain the swapOutM function is called to convert the M extension tokens to $M

    tokens

    • The $M tokens are transferred to the destination chain
    • On the destination chain the system tries to wrap the $M tokens to M extension tokens with the

    swapInM function

    • But in case the swapInM call fails the user just receives the $M tokens instead

    This is problematic as normal users should never receive $M tokens and as a normal user is not able to use the swapInM function the user might not be able to do anything with these tokens.

    A malicious actor might also be able to do this on purpose (in case the actor sees any benefit of doing so).

    For example if the M extension token has a minimum amount restriction for the wrap function of $100 the user could perform multiple $99.99 cross chain transfers to load himself up with $M tokens.

    Recommendation

    Consider leaving the tokens inside the contract or transferring them to another one and let an admin handle the situation if this edge case occurs.

    Resolution

    M0 Team: Acknowledged. This is acceptable behavior for now.

  3. I-01 Informational Incorrect Comment Informational Acknowledged
    Location
    SpokePortal.sol: 128

    Description

    The comment above the _revertIfUnsupportedDestinationChain function on line 128 of SpokePortal contract is incorrect. It should be: "Reverts if the destination chain is not the Hub chain".

    Recommendation

    Update the comment.

    Resolution

    M0 Team: Acknowledged. Will fix.

  4. I-02 Informational Earning Cannot Be Re-Enabled Once Disabled Warning Acknowledged
    Location
    HubPortal.sol: 200-201

    Description

    The _isEarningEnabled function is implemented as:

    function _isEarningEnabled() internal view returns (bool) {
        return wasEarningEnabled & disableEarningIndex = IndexingMath.EXP_SCALED_ONE;
    }
    

    Given this logic:

    Once disableEarningIndex is set to current Index in disableEarning, earning can not be enabled again.

    Recommendation

    Be aware of this constraint.

    Resolution

    M0 Team: Acceptable behavior.

More from M0

All 10 reports
  1. Liquidity Delivery Updates

    4 findings 4 findings: 1 low, 3 informational
  2. PYUSDX

    21 findings 21 findings: 8 low, 13 informational
  3. Liquidity Delivery

    59 findings3 critical · 5 high 59 findings: 3 critical, 5 high, 10 medium, 14 low, 27 informational
  4. M Extensions Updates

    16 findings 16 findings: 1 medium, 5 low, 10 informational

Put your code through the same review.

This review started with a conversation about scope. Tell us what you are building and we will plan yours with you.

Get a quote