Verus Incident Analysis

Research Incident Analysis
Verus Incident Analysis

Incident Summary

On July 23, 2026, an attacker exploited the Verus Protocol’s Ethereum cross-chain bridge, draining approximately $7.44 million in ETH, tBTC, stablecoins, and MKR. The attack relied on a discrepancy in how Verus and Ethereum interpreted notarization data: malicious duplicate state-root entries were included in otherwise legitimate notarizations, signed by Verus notaries, and then relayed to Ethereum, where they overwrote the genuine trusted state root. Using this attacker-controlled root, the attacker submitted a fabricated bridge import proof that authorized inflated withdrawals despite initiating only a 0.01 VRSC export.

Background

A Verus “notarization” is a signed, on-chain cross-chain checkpoint. It establishes the root against which later transaction/export proofs will be verified. It contains:

  • which system/currency it represents
  • the notarization height
  • one or more proofRoots:system ID
    • chain height
    • state/proof root
    • block hash
    • accumulated power
    • currency and converter state
    • a pointer to the preceding notarization
    • a hash linking to the previous cross-chain notarization
    • proposer and node information

The proof roots are derived from public Verus/Ethereum chain data https://github.com/VerusCoin/VerusCoin/blob/a10e2fb39e42a7c31d4e447c9e152090a562a57f/src/pbaas/notarization.cpp. Anyone may submit or relay a candidate notarization, but nodes accept it only if it spends the correct notarization-thread UTXO and supplies the required consensus evidence. https://github.com/VerusCoin/VerusCoin/blob/a10e2fb39e42a7c31d4e447c9e152090a562a57f/src/pbaas/notarization.cpp The CNotarySignature was public evidence inside CNotaryEvidence, published through EVAL_NOTARY_EVIDENCE; the attacker could harvest and relay it.

Key Transactions (Times in UTC)

Timestamp Transaction / Explanation
Jul-22-2026 23:17 Genuine notarization
23:49 First notarization containing malicious state root
23:59 Second notarization containing malicious state root
Jul-23-2026 01:48 Initiate export request through Bridge.vETH
01:51 Package the request for converter
01:51 Emit actual cross chain transfer
01:51 Batch transfer through LuckPool
03:08 Third notarization containing malicious state root
03:23:35 First call SetLatestData(), relaying second notarization
03:41:47 Second call SetLatestData(), relaying third notarization
03:45:59 ~$7.44M drained

Key Addresses

Address Label
RXo2PqXjgRVJ8w8QVDErVqVLavz4TToyuu Attacker on Verus
0xBda71b58cEc0b1C20A8f87cCD52FA0679747855c Attacker address on ETH
0xCFd0A20703cD11E0b9f665e1C3F1Ef989C142D54 Attacker profit address on ETH
i3f7tSctFkiPpiedY8QR5Tep9p4qDVebDx Bridge.vETH on Verus
0x71518580f36FeCEFfE0721F06bA4703218cD7F63 Verus: Ethereum Bridge
0x54e03a1682fd0bb065b669f6296f97028dcfd4ce VerusProof contract

Attack Flow

1. Notarization poisoning on Verus:

Transaction 1 spent the previous accepted-notarization output 4f4f…:1 and created 0c247…:0. Referencing notarization.cpp, the notarization reads: Referencing notarization.cpp, the notarization reads: verus1 Only the two legitimate ones were visible on scan.verus in “Raw Data” verus2 Because Verus reads the serialized roots into a vector then inserts them into a map, verus3 https://github.com/VerusCoin/VerusCoin/blob/a10e2fb39e42a7c31d4e447c9e152090a562a57f/src/pbaas/pbaas.h

two successive transactions expends previous notarization output, and secretly submitting 2 and 3 more malicious state-root entries respectively of verus4

2. State root injection on Ethereum:

The attacker waited for the notary software to validate the innocent first roots then 11 legitimate notary daemons sign the raw Verus notarization, including the ignored duplicates containing malicious state root.

New signatures are wrapped in a CNotarySignature, placed inside CNotaryEvidence, and serialized into an EVAL_NOTARY_EVIDENCE CryptoCondition output verus5 The attacker calls getnotarizationdata() →…-> GetUnspentEvidence() from Verus RPC to retrieve and extract the signatures and packages them into setLatestData() on Ethereum. verus6 On Ethereum, the attacker acts as broadcaster, copying the relevant bytes from Verus and the signatures and placing them in setLastdata() calldata (https://etherscan.io/tx/0x8f21bd8f0fce72ac959caa93a9923d85f902dfc6eddac2785ac5bc49c3b28d8f and https://etherscan.io/tx/0x51b1c8341da4092b7d1e0e4865f7b318de4e96245358b05b2bff2df50adaf0c9)

Upon deserializeNotarization() verus7 The ‘proofRoots’ are processed in a loop, and stateRoot is overwritten for every “system==ID” entry verus8 Therefore Entry 1 genuine Verus root → stateRoot = genuine Entry 2 Ethereum root → no Verus assignment Entry 3 malicious Verus root → stateRoot = 20f2…d30a Entry 4 malicious Verus root → stateRoot = 20f2…d30a Entry 5 malicious Verus root → stateRoot = 20f2…d30a The false later entries overwrites the first genuine one, successfully injecting the ‘stateRoot’ attacker’s subsequent bridge import proof would derive to. verus9

3. Set up bridge export on Verus:

In transaction 5b5043febfd7f7c089e976d11d0f87a904881266bb96dd118b3d69b0e02aab52 a fresh address initiated a 0.01 VRSC cross-chain request, with a ~12 fee supplied through Bridge.vETH. verus10 The request was then processed by the converter and LuckPool exported the batch in transaction e26e270d33543520abf4948980edbe62adf85564e512f43cc6da0808ca4e09a6. verus11 Notably the request included the following data, which part of the proof components will be based on:

hashtransfers: 440787f9114dbb41b7d3d6f6c48980d51221f62ef0a33613d1d305b98ae85053 "sourceheightend": 4162847” "sourceheightstart": 4162638

4. Call submitImports() to drain bridge on Ethereum:

Of the 14 CCE fields, the notable changes are hashtransfers, which are fabricated to match the draining transfers hash. ‘numInputs is changed to 8, firstinput is change to 0 verus12 Besides totalamounts, totalfees and totalburned are omitted (Version / flags / sourcesystemid / hashtransfers / sourceheightstart / sourceheightend / destinationsystemid / destinationcurrencyid / numinputs / totalamounts / totalfees / totalburned / rewardaddress / firstinput)

Of the proof components, the reused parts were:

  • Txid: 7bdd56c52376ae63aa2007e1d8e1694d8413bdc95709dfe442f77285765f5938
  • First node: 75f5a00b1f2d9b0d898a4d81b00d417d0123684e05bb4af6813adfe08cce0aee

and public format/constants (proof version, types and system identifiers) verus13 While the rest are arbitrarily constructed the derived final MMR result of which, the attacker had already injected in step 1 and 2 as state root.

Vulnerability

The primary failure is due to cross-chain semantic consistency, the attacker caused Verus notaries to authorize bytes that Verus understood as containing the genuine checkpoint.

Verus reads the serialized roots into a vector then inserts them into a map while Ethereum interpreted the same bytes as containing an attacker-controlled checkpoint. verus14 Once Ethereum confirmed 20f2…d30a as its trusted Verus root, a fabricated export proof constructed under that root could be accepted as authentic. verus15 An additional factor is a logic flaw in Verus’s Ethereum bridge contract, which did not verify that the payout amount specified in an import request corresponded to the value actually exported on the Verus network. verus16 A ‘hashtransfers’ fabricated to match the draining transfers hash is enough to pass the CCE verification.

Fund Flow

Following the exploit, the attacker swapped the stolen assets for 2,778.8662 ETH via Relay then deposited the funds into Tornado Cash. verus17

To keep up to date on the latest incident alerts and statistics, follow @certikalert on X, or read our latest analysis on certik.com.

Related Blogs

DefiTuna Incident Analysis

DefiTuna Incident Analysis

On 16 July 2026, DeFiTuna was exploited for approximately $569,601 USDC on Solana. The attackers created a highly illiquid TUNA/USDC pool and used it as the destination for borrowed USDC routed through Jupiter. Because the swap returned only a negligible amount of TUNA, DeFiTuna’s value calculation rounded the position’s total assets down to zero. The protocol then incorrectly treated the position as healthy, allowing the attackers to bypass the solvency check and withdraw the USDC through attacker-controlled liquidity positions.

GnosisPay Incident Analysis

GnosisPay Incident Analysis

On 01 June 2026 an attacker drained dozens of GnosisPay Safes on Gnosis Chain. The attack vector was a signature-verification flaw in the GnosisPay Delay module.

Resolv Protocol Incident Analysis

Resolv Protocol Incident Analysis

On 22 March 2026, the Revolv protocol was exploited, resulting in a loss of ~$26.8M due to a compromise of the project's cloud infrastructure which gave access to Resolv’s AWS Key Management Service (KMS).