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:
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.
I reproduced this with a minimal two-instance setup using the target commit.
OverlayerWrapMock contracts, one acting as the source instance and one acting as the destination instance.testDebit() on the source instance. This goes through the same _debit() path and burns the user's OVA on the source side.totalBridgedOut == bridgeAmount.testCredit() on the fresh destination instance with the same amount.0x11 because the destination's local totalBridgedOut is still zero.Exact command used:
npx hardhat test --network hardhat test/poc/OverlayerWrapCrossChainLock.ts
Observed result:
1 passing0x11This proves the funds are burned before the destination credit fails.