Status DataClose notification

Overlayer Disclosed Report

First inbound OFT credit on a non-hub chain reverts and permanently locks bridged user funds

Company
Created date
Apr 03 2026

Target

hidden

Vulnerability Details

Summary

OverlayerWrapCore uses totalBridgedOut to preserve the hub-chain backing invariant. _debit() adds to it and _credit() subtracts from it on every chain.

The first inbound bridge transfer to a non-hub deployment reverts in _credit() because that destination instance starts with totalBridgedOut == 0, so totalBridgedOut -= amountReceivedLD underflows.

Because the source OFT debit already burned the user's source-chain balance before the destination credit runs, the user's funds are trapped in the failed cross-chain message flow.

Affected code

  • contracts/overlayer/OverlayerWrapCore.sol:63
  • contracts/overlayer/OverlayerWrapCore.sol:510
  • contracts/overlayer/OverlayerWrapCore.sol:537

Root cause

totalBridgedOut is hub-chain accounting, but both _debit() and _credit() update it unconditionally on all deployments. A fresh satellite chain has no prior outbound amount, so its first inbound credit always executes 0 - amountReceivedLD.

Attack scenario

  1. User holds OverlayerWrap on the hub chain.
  2. User bridges hub -> satellite using the standard OFT flow.
  3. Source _debit() burns the user's source balance and increments totalBridgedOut.
  4. Destination _credit() runs on the non-hub deployment with local totalBridgedOut == 0.
  5. totalBridgedOut -= amountReceivedLD underflows and reverts.
  6. Destination mint never happens while the source tokens are already burned.

Impact

This matches the program's Critical scope:

  • no privileged role is required
  • exploitability is deterministic on the first inbound transfer to a fresh non-hub instance
  • end-user funds are permanently locked in the failed bridge flow unless the protocol is patched or manually recovers the message

Validation steps

PoC files attached

  • overlayer-bridge-lock-poc.zip
    • audit/HACKENPROOF-01-bridge-first-inbound-credit-locks-funds.md
    • test/audit/OverlayerWrapBridgeLock.ts
    • contracts/test/MockLayerZeroEndpointV2.sol
    • hardhat.audit.config.ts

How to run

  1. Extract the zip.
  2. From the repo root run: npx hardhat test test/audit/OverlayerWrapBridgeLock.ts --config hardhat.audit.config.ts

Expected result

The test passes and proves that the first hub -> satellite bridge transfer locks funds because the destination _credit() underflows while the source-side burn has already happened.

Observed test name: locks the first hub->satellite transfer because destination _credit underflows

Suggested fix

Restrict totalBridgedOut accounting to the hub chain only:

  • increment in _debit() only on the hub chain
  • decrement in _credit() only on the hub chain

Alternatively, split the accounting into separate outbound-from-hub and inbound-to-hub variables instead of using one per-chain counter.

Post-fix validation

  1. First hub -> satellite transfer succeeds on a fresh satellite deployment.
  2. Satellite -> hub return transfer still preserves totalSupply() + totalBridgedOut on the hub chain.
  3. Fresh non-hub instances can receive inbound transfers without any prior outbound bridge.

Attachments

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