Status DataClose notification

Overlayer Disclosed Report

Cross-chain receive underflow can permanently lock bridged user funds

Company
Created date
Apr 02 2026

Target

hidden

Vulnerability Details

Severity

Critical

Affected Scope

  • contracts/overlayer/OverlayerWrapCore.sol

Root Cause

The destination credit path in OverlayerWrapCore unconditionally decrements totalBridgedOut:

  • contracts/overlayer/OverlayerWrapCore.sol:543

On a fresh destination deployment, totalBridgedOut is zero before any local outbound bridging occurs. If the first cross-chain operation is an inbound credit, the subtraction underflows and reverts.

Vulnerable Code

function _credit(
    address to_,
    uint256 amountLD_,
    uint32 srcEid_
) internal virtual override returns (uint256 amountReceivedLD) {
    amountReceivedLD = super._credit(to_, amountLD_, srcEid_);
    totalBridgedOut -= amountReceivedLD;
}

Attack Scenario

  1. A user bridges OverlayerWrap from hub chain to a destination chain.
  2. Source-side debit executes, and the bridged amount is burned on source.
  3. The LayerZero message is delivered to destination and _credit is called.
  4. Destination has totalBridgedOut == 0 (no prior local outbound bridge history).
  5. totalBridgedOut -= amountReceivedLD underflows and reverts.
  6. Credit does not complete and user funds remain stuck in failed cross-chain delivery flow.

Impact

  • Direct lock risk for bridged end-user funds.
  • First inbound bridge on a destination deployment can fail deterministically.
  • Potential aggregate lock can be significant as usage grows.

Recommendation

  1. Restrict bridged-out accounting to hub chain only.
  2. Add chain guard around accounting mutation in _debit and _credit, for example mutate totalBridgedOut only when block.chainid == hubChainId.
  3. Add invariant tests for first-ever inbound credit on a destination instance with no prior local debit history.

Validation steps

Runnable PoC

A runnable regression test has been added:

  • test/OverlayerWrap.ts:1223

PoC Test Name

Should revert on first inbound credit when no prior local debit exists

Why this reproduces the bug

The test calls testCredit on a fresh deployment before any testDebit, so totalBridgedOut is zero and the vulnerable subtraction is reached.

Expected Result

  • The test passes because testCredit(...) reverts as expected.
  • This demonstrates deterministic failure of first inbound credit flow under current logic.

Additional Evidence

  • Cross-chain accounting block in OverlayerWrapCore:
    • contracts/overlayer/OverlayerWrapCore.sol:501
    • contracts/overlayer/OverlayerWrapCore.sol:541
  • Existing tests currently focus on debit then credit round-trips on same instance:
    • test/OverlayerWrap.ts:1222

Attachments

hidden
CommentsReport History
Comments on this report are hidden
Details
Statedisclosed
Severity
Critical
Bounty$69
Visibilitypartially
VulnerabilityOther
Participants
hidden