
Date: July 23, 2026
Chain: Ethereum
Loss: about $7.54M in ETH, tBTC, stablecoins, MKR and freshly minted DAI
Class: cross-chain import accepted a transfer list without checking the value behind it
At 03:45:59 UTC on July 23, 2026, a single call to submitImports on the Verus-Ethereum Bridge sent 1,137.45 ETH, 71.50 tBTC, 149,275 USDC, 78,300 USDT, 31,475 EURC, 59.43 MKR and 92,784 scrvUSD to one wallet, and the bridge minted another 220,357 DAI against its own Maker position to cover the rest. The export on the Verus side that the attacker had set up beforehand moved 0.01 VRSC.
It was the second time in 66 days that the bridge paid out against value that was never locked. In May, an attacker drained about $11.58M through a function called checkCCEValues, and the team patched it. In July, the attacker went through a newly deployed version of its sibling, VerusProof.checkExportAndTransfers, which confirmed that a list of transfers matched the hash committed in a Verus export but never read whether the export carried enough value to back them.
The Verus-Ethereum Bridge moves value between the Verus chain and Ethereum without a central custodian. When someone sends assets from Verus to Ethereum, Verus records a CrossChainExport, a structured output that commits to a specific batch of reserve transfers by hashing them. Verus notaries sign notarizations of the Verus state, each carrying a proof root that summarizes the chain at a given height. Those notarizations are relayed to Ethereum, the bridge contract checks the signatures, and once a notarization is confirmed, any export can be proven against its proof root. If the proof passes, the bridge releases the matching assets from its reserves.
That design makes the export work like a receipt. The Ethereum contract never sees the Verus funds directly, so everything it pays out depends on what the receipt says and how carefully the contract reads it. In its August 1 write-up, the Verus team described the contract as an EVM-tailored subset of its cross-chain protocol that only works if the contract reads every serialized object exactly the way a Verus node does.
On Ethereum, the bridge is a contract named Delegator at 0x7151...7F63, verified on Blockscout since December 2024. It holds the reserves and keeps a registry of logic contracts by role, then delegatecalls into them, so the logic runs against the Delegator's own storage and balances. Its submitImports function looks up the SubmitImports logic contract and delegatecalls _createImports with the caller's data. Blockscout's trace of the July exploit transaction shows the Delegator delegatecalling into the VerusProof contract at 0x54e0...d4ce during that process. By July 2026 the bridge held ETH, tBTC, stablecoins and other tokens, and a Maker collateral position that let it mint DAI when a withdrawal called for it. Rekt notes that DefiLlama put the bridge's value locked at roughly $90M at the start of 2025 and under $5M by late July 2026.
The first exploit hit on the night of May 17 to 18, 2026. Merkle Science reports that the bridge paid out 1,625 ETH, 103 tBTC and 147,000 USDC, about $11.58M in total, because checkCCEValues never verified that the export's total value matched the payout claimed on Ethereum. Verus later described that first attack as putting an output on Verus that real notarizations could prove, which the contract then read as a different output type than the Verus daemon did.
On May 21 the Verus community posted bounty terms to the exploiter, and on May 23 it confirmed that 4,052.4 ETH, around 75% of the stolen funds, had come back to a community-controlled return address, with the attacker keeping 1,350 ETH as a bounty. By May 28, the recovery address held 1,194.86 ETH, 76.0321 tBTC and 147,727.67 USDC after converting the returned ETH back into the original currencies.
Rekt reports that Verus released v1.2.17, an urgent bridge restoration release, on July 3, and that about 1,192 ETH moved from the recovery address back into the bridge contract on July 8. Blockscout shows the VerusProof contract the bridge was calling on July 23 was created on July 10 at 11:13:47 UTC in block 25501817, and Rekt adds that v1.2.17-1, released July 12, added an opt-out vote for the Ethereum contract upgrade. The code that failed in July had been on mainnet for 13 days.
From the verified VerusProof source on Etherscan and Blockscout (contracts/MMR/VerusProof.sol), this is the part of checkExportAndTransfers that runs once the function reaches the proven transaction output:
The first two lines take the raw bytes of the proven output and its position in the Verus transaction. _parseCTxOut then confirms the output's script has the shape of a cross-chain export and finds where the export body starts, and _readCCEFields decodes that body into a CCEData struct. The final if block is the whole validation: the hash of the transfers the caller submitted must equal hashReserveTransfers inside the export, the export must come from Verus, and it must be headed to Ethereum's vETH system and currency. Earlier in the same loop, the function requires that at least one input of the Verus transaction spends the last export the bridge processed. If all of that holds, the function returns the export's heights, its output index and its number of transfers, and the caller goes on to pay those transfers out.
The struct the decoder fills tells the rest of the story. From the same verified file:
Every field the import check decodes is about routing and identity: where the export came from, where it's going, who exported it, how many transfers it holds and which blocks it covers. None of them is an amount. The export's totalamounts, totalfees and totalburned, and the output's nValue, which is the value actually locked on Verus, are never decoded, so nothing downstream can compare them with what the transfers ask for. That matches the root cause SlowMist disclosed, and CertiK lists the same missing comparison between payout and exported value.
A hash commitment proves that a particular list was declared. It can't say whether anyone locked the value that list asks for, and whoever builds an export chooses both the list and the hash that commits to it. Think of a cashier who checks that a receipt's printed total matches the items listed on it, but never checks whether the customer paid. For a bridge, the rule that matters is that every payout on Ethereum has to be backed by value the export proves was locked on Verus, and this import path never compared the two.
CertiK's timeline starts on the Verus side the evening before. A genuine notarization landed at 23:17 UTC on July 22, followed by two notarizations carrying extra, malicious proof-root entries at 23:49 and 23:59. At 01:48 UTC on July 23, a fresh address started a 0.01 VRSC cross-chain request through the Bridge.vETH currency, which was packaged and exported in a batch by 01:51, and a third malicious notarization followed at 03:08. Rekt describes the same small transfer as the move that made the attacker's export the most recent one, which satisfied the check that each import spends the previous export.
The attacker then moved to Ethereum. Two SetLatestData() calls, at 03:23:35 and 03:41:47 UTC, relayed the second and third notarizations to the Delegator, each carrying signatures from eleven notaries. At 03:45:59, in block 25592836, the attacker's EOA 0xBda7...855c called submitImports with an import claiming eight reserve transfers. CertiK reports that the fabricated export set numInputs to 8 and firstinput to 0, and that the attacker reused a txid and first proof node from a legitimate proof.
Blockscout's trace shows the payouts in order. The Delegator sent 1,137.45 ETH straight to the receiving wallet 0xCFd0...2D54, then transferred 71.50 tBTC, 59.43 MKR, 149,275.07 USDC, 78,300.54 USDT, 31,475.66 EURC and 92,784.36 scrvUSD, and the receiving wallet also got 220,357.03 DAI minted from the zero address, which is the bridge drawing on its Maker position rather than its own balance.
The published accounts agree on the missing value check and differ on how the forged export reached a state the bridge trusted. SlowMist and Rekt describe the export as sitting inside a legitimately notarized Verus state. CertiK and the Verus team describe something deeper. In Verus's own explanation, proof roots in a notarization are stored in a map, and when the Verus daemon reads two entries with the same key it keeps the first and ignores the second, while the contract's deserializeNotarization() overwrote the stored root with the later one. Notaries signed bytes that Verus read one way and Ethereum read another, so the contract ended up holding a proof root the attacker had built, and the export proven against it never existed on Verus at all. In SlowMist's and Rekt's reading, a check on the export's value would have stopped the payout. In Verus's reading, the attacker also controlled the proof root, and the bridge's last line was still the check quoted above, which never looked at value.
Etherscan shows how the proceeds came together. Within minutes, ten transfers from the Relay router between blocks 25592896 and 25592973 added about 2,778.8 ETH to the receiving wallet from swapping the other tokens, which with the 1,137.45 ETH paid directly makes about 3,916 ETH, the figure Rekt reports, while CertiK's 2,778.8662 ETH is the Relay portion alone. PeckShield flagged the drain and noted the exploiter was already moving funds into Tornado Cash. Rekt reports the deposits began about 90 minutes after the exploit, stepping up from 0.1 ETH through 1 ETH and 10 ETH to a long series of 100 ETH transfers, and that the receiving wallet later held about 0.09 ETH. The Block reports that Blockaid tied the attack to the May exploit's contract, entry path and vulnerability class while attributing it to a different attacker using a new wallet.
The Verus team answered on August 1 with a long post on its X account. It said both exploits came from asymmetries between Verus's serialization and the Ethereum contract's parsing, that the work had been reviewed by multiple people and AI tools after the fact, and that the July attackers never proved any real export on Verus. It laid out a fix in layers: close every known parsing asymmetry, then hold released funds for a period during which a majority of witnesses can confirm the export over Verus's own RPC, or a delay, which it put at 8 or 12 hours, passes without anyone stopping the payout. For losses, the team said it would replace 99.9% of the currency lost in July with a usage-based restitution currency, as it planned for the first exploit.
Verus shipped v1.2.18 on September 17 as a critical security update. As of October 20, 2026, its most recent monthly update, the September Verus View published October 5, still described the Ethereum contract upgrades as planned, with a witness check in which four witnesses rejecting a transfer can stop contract processing and a longer delay applies to transfers that aren't confirmed. Nothing from the July drain has been reported recovered.
Verus's August 1 post is direct about its security process. It says the team hasn't commissioned an official third-party audit, mostly because of funding, and relies on experienced developers and security researchers using AI tools. It also says the core assumption that failed was that custom Solidity could match Verus's serialization exactly after review by multiple people and AI tools, and that the second asymmetry was missed in the initial work and in several later reviews. Rekt names no audit firm for either version of the bridge contracts.
The pattern in the timeline is common in patched systems. The May fix closed checkCCEValues, and the restoration release brought a new VerusProof contract to mainnet within days, so the code that mattered in July was both new and written against the lesson of a different function. Line-by-line review answers whether each function does what it says, while a bridge's safety depends on a rule that spans the whole import flow. Verus states that rule itself in the August 1 post: only funds backed by real, funded exports on Verus should ever be released, an invariant it says has held for the life of the protocol on the Verus side.
Olympix reads a contract the way an attacker does, as states, transitions and entry points, and it takes in the context around the code, such as the export format and the upgrade history, to infer the invariants the system depends on. For this bridge, the state that matters is how much of each reserve asset the Delegator holds and the record of the last export it processed, and the entry point that changes both is submitImports. The signal in the quoted code is concrete: a payout whose size comes from caller-supplied transfers, gated by a check whose decoded struct has no amount field at all, so the only link between the transfers and the export is a hash the same party can produce. The engine flags that kind of path, where values flow into token transfers without passing through any comparison with a locked amount.
The invariant in one sentence: the value the bridge releases for an import must never exceed the value the matching Verus export proves was locked. A contract's state space looks infinite, but it isn't. The engine maps every path from the Delegator's entry points, keeps the feasible ones that can pass the signature, proof and export checks, and narrows those to the ones that end in a reserve transfer or a DAI mint, since those are the only paths that can touch the invariant. BugPoCer then runs Counterexample-Guided Invariant Refutation on that set, starting from the bridge as a whole and executing each path until a sequence releases more than the export locked.
The counterexample for this exploit would read like the July 23 transaction in miniature. A low-value export becomes the last processed export, a successor export spends it and commits by hash to transfers worth far more, and an import submits those transfers with a matching hash. The minimal conditions are the ones in the quoted code: an input that spends the last export, a matching hashReserveTransfers, a Verus source and a vETH destination, with no condition at all on the export's value. BugPoCer returns that sequence along with a generated Forge test that sets up the bridge state, submits the import and asserts that the reserves dropped by more than the export carried. Because that test checks the rule rather than a function, it fails against checkExportAndTransfers exactly as it would have failed against checkCCEValues in May.
Olympix runs automatically in development, at every merge and before release. Here that means the merge that introduced the July 10 VerusProof contract, before the restoration release and the contract upgrade vote, is where the failing test would have shown up. This finding covers the missing value check that SlowMist, Rekt and CertiK all name. The notarization parsing difference CertiK and Verus describe is a separate asymmetry between the Verus daemon and the contract, and this post doesn't claim the same test would have caught it.
The May and July exploits went through different functions but broke the same promise, that the bridge only pays out what Verus actually locked. Signatures and Merkle proofs show that a message exists and say nothing about whether it's worth what it claims, so a bridge's cryptographic checks can all pass while that promise goes untested. Writing the economic rule down as an invariant and testing every path that reaches a payout against it is how a fix for one function turns into coverage for the whole boundary, including the next contract a fix ships with. To see how Olympix maps the paths from your own contracts' entry points to the funds they release, book a technical walkthrough.
Protocol: Verus-Ethereum Bridge
Chain: Ethereum
Date: July 23, 2026, 03:45:59 UTC
Block: 25592836
Loss: about $7.54M per Rekt, about $7.44M per CertiK
Attacker EOA: 0xBda7...855c
Receiving wallet: 0xCFd0...2D54
Bridge contract (Delegator): 0x7151...7F63
Vulnerable contract (VerusProof): 0x54e0...d4ce
VerusProof deployment tx (July 10, 2026, 11:13:47 UTC, block 25501817): 0xa7e6...92d6
Recovered ETH returned to the bridge (July 8, 2026): 0x3144...83a7
First SetLatestData() tx: 0x8f21...8d8f
Second SetLatestData() tx: 0x51b1...f0c9
Exploit tx (submitImports): 0xa1f1...b099
CertiK: Verus Incident Analysis
Verus on X: The Latest Ethereum Bridge Exploit, What Happened and What Comes Next
SlowMist: Verus Bridge root cause alert
Merkle Science: Hack Track, The $11.58M Verus Bridge Hack
The Block: New Verus-Ethereum bridge attack drains $7.5 million