Status DataClose notification

Overlayer Disclosed Report

OverlayerWrap cross-chain credit accounting permanently locks bridged OVA on the first inbound transfer

Company
Created date
Apr 06 2026

Target

hidden

Vulnerability Details

The bridge accounting added around totalBridgedOut is tracked in local storage on each chain, but the code treats it like a global cross-chain liability counter.

The relevant logic is in:

On the source chain, _debit() calls super._debit(), which burns the user's OVA, and then increases the source chain's local totalBridgedOut.

On the destination chain, _credit() calls super._credit() and then decreases the destination chain's local totalBridgedOut.

That is the core issue. The destination instance has its own storage and, on a fresh deployment, totalBridgedOut starts at 0. So the first inbound transfer into that destination attempts:

0 - amountReceivedLD

and reverts with arithmetic underflow.

The end result is much worse than a normal bridge failure:

  1. The source-side burn has already happened.
  2. The destination-side mint/credit reverts.
  3. The user no longer has the bridged OVA on the source chain.
  4. The user does not receive the OVA on the destination chain.

This creates a permanent lock path for bridged user funds.

This is also not the same issue as Hacken's previous F-2026-1525. That earlier finding was a supply() DoS caused by hub-chain supply reduction after OFT transfers. The current bug comes from the new totalBridgedOut bookkeeping that was introduced to address that problem. In other words, the old issue was about backing accounting on the hub chain; this issue is about destination-side _credit() underflow that strands user funds after the source burn has already completed.

This is a high-likelihood issue because it does not require privileges, large capital, or unusual timing. A normal user performing a standard bridge transfer into a newly deployed destination instance is enough to trigger it. The locked amount is the full bridged amount for that user, so the impact easily exceeds 1% of the user's deposit.

Validation steps

I reproduced this with a minimal two-instance setup using the target commit.

  1. Deploy two separate OverlayerWrapMock contracts, one acting as the source instance and one acting as the destination instance.
  2. Mint OVA to the user on the source instance.
  3. Call testDebit() on the source instance. This goes through the same _debit() path and burns the user's OVA on the source side.
  4. Observe that the source instance now has totalBridgedOut == bridgeAmount.
  5. Call testCredit() on the fresh destination instance with the same amount.
  6. The call reverts with panic 0x11 because the destination's local totalBridgedOut is still zero.
  7. Confirm that the destination total supply is still zero after the revert.

Exact command used:

npx hardhat test --network hardhat test/poc/OverlayerWrapCrossChainLock.ts

Observed result:

  • 1 passing
  • source-side debit succeeds
  • destination-side credit reverts with panic 0x11

This proves the funds are burned before the destination credit fails. uploaded-image

Attachments

hidden
CommentsReport History
Comments on this report are hidden
Details
Statedisclosed
Severity
Critical
Bounty$69
Visibilitypartially
VulnerabilityDoS with (Unexpected) revert
Participants
hidden