Votemarket Incident Disclosure - 12-03-2026

Summary

On March 12, 2026, a vulnerability affecting a peripheral oracle update mechanism used by Votemarket was exploited, resulting in the unauthorised extraction of approximately $175,000 in campaign incentive rewards. Core protocol contracts and user deposits were not affected. The issue has been contained and the relevant oracle updater contracts have been revoked while remediation steps are being evaluated.

Details

On March 12, 2026, a vulnerability in the L1BlockOracleUpdater peripheral contract appears to have been exploited to inject fabricated L1 block data into the Votemarket Oracle on Arbitrum and Base via the LaPoste cross-chain messaging bridge. By poisoning the Oracle state, the address performing the transactions (the "attacker") forged Merkle Patricia storage proofs to register fictitious vote data and subsequently drained campaign rewards across 54 campaigns (50 on Arbitrum and 4 on Base), totaling approximately $175,000 in unauthorised extraction of campaign incentive assets (stolen). Legitimate voters' claims for the affected epochs were consumed, preventing legitimate claimants from receiving their rewards for the affected epochs until remediation is implemented.

Severity: Critical
Affected Protocol: Votemarket V2 (peripheral oracle infrastructure)
Core Contracts Affected: No. The Votemarket core contracts are not affected by this vulnerability.

Stolen Assets Breakdown

AssetAmount
SPELL~117.3M
DOLA~66,805
opASF~57,596
WFRAX~40,154
pmUSD~36,000
CRV~30,960
ASF~21,598
USDC~7,170
USDC~5,828
sdUSD~1,673
GHO~1,200
USDp~960
CVX~480
MUSD~360
OUSD~143

Background

Votemarket V2 uses storage proofs to trustlessly verify Curve GaugeController vote data from Ethereum L1 on L2 chains. The architecture relies on the following components:

  1. L1BlockOracleUpdater (peripheral, permissionless): Receives L1 block headers (number, hash, timestamp) and writes them to the Oracle. It can be updated either directly from the L1 block oracle or via cross-chain messages through LaPoste. This is not part of the Votemarket protocol itself. It is a convenience mechanism for anyone to push L1 block data to the Oracle without requiring a privileged operator.
  2. Verifier: Validates Merkle Patricia proofs against the block header stored in the Oracle to extract vote slopes, weights, and timestamps from the GaugeController's storage.
  3. Oracle: Stores the verified L1 block and vote data, which the Votemarket contract reads to calculate reward distributions.
  4. Votemarket: Distributes campaign rewards proportionally based on Oracle data. Anyone can trigger a claim for any account, with tokens sent to the account or its designated recipient.

Root Cause Analysis

The vulnerability was introduced on October 21, 2024 and remained undetected in production for approximately 17 months.

It resided in the sender validation logic of L1BlockOracleUpdater.receiveMessage():

function receiveMessage(uint256 chainId, address sender, bytes memory data) external onlyLaPoste {
    if (chainId != 1 && sender != L1_SENDER && sender != address(this)) revert WrongSender();
    // ...
}

The conditional uses && (AND) across all three checks. When chainId == 1 (Ethereum mainnet), the first operand chainId != 1 evaluates to false, which short-circuits the entire expression to false, the revert is never triggered. Any address sending a cross-chain message from Ethereum mainnet through LaPoste was accepted as a valid sender, completely bypassing the authorization check.

Attack Flow

Step 1: Inject Fabricated L1 Block Data

The attacker sent two cross-chain messages from Ethereum mainnet through LaPoste targeting the L1BlockOracleUpdater on Arbitrum and Base. Since chainId == 1, the sender validation was bypassed entirely on both chains. The payload contained fabricated block data:

  • blockNumber: 99999999 (non-existent block)
  • blockHash: attacker-chosen hash
  • timestamp: 1773273700 (mapping to the current epoch 1773273600, March 12)

Step 2: Register Fabricated Block Header

The attacker called Verifier.setBlockData() with an RLP-encoded block header whose keccak256 hash matched the previously injected fabricated block hash. This crafted header contained a stateRootHash pointing to a Merkle trie the attacker fully controlled. The accompanying account proof resolved to a fabricated "GaugeController" account with an attacker-controlled storage root.

Step 3: Register Fabricated Vote Data

The attacker called Verifier.setAccountData() and Verifier.setPointData() for their own address with crafted storage proofs against the fabricated storage root, registering arbitrarily large vote slopes in the Oracle across all targeted campaigns. The Verifier's ALREADY_REGISTERED check only prevents duplicate writes. Since no legitimate data existed yet for the poisoned epoch, these writes succeeded without resistance.

Step 4: Drain Campaign Rewards

The attacker called updateEpoch() followed by claim() on the Votemarket for their own address across 50 Arbitrum campaigns, receiving rewards proportional to their inflated fabricated vote data. This consumed each campaign's reward budget, effectively stealing claims that belonged to legitimate voters.

Step 5: Bridge and Launder Proceeds

The attacker bridged stolen assets from Arbitrum to Ethereum via LaPoste/CCIP, manually executing stuck CCIP messages on the Ethereum OffRamp. Once on Ethereum, stolen tokens were swapped through Uniswap V3, SushiSwap, and Curve pools into fungible assets (ETH, DAI, USDC), then transferred to external addresses.

Affected Campaigns

ChainCountCampaign IDs
Arbitrum501191-1240
Base482, 84, 85, 86

Arbitrum: WFRAX, DOLA, pmUSD, opASF, ASF, SPELL, USDC, GHO, sdUSD, CVX, MUSD, OUSD
Base: USDC, USDp, CRV

Vulnerable Contracts

The same receiveMessage vulnerability exists in both the single-oracle and multi-oracle versions of the L1BlockOracleUpdater. The multi-oracle version, deployed at 0xAe74643A86CA9544A41c266bC5bf2D26479f64E7, feeds 5 Oracles simultaneously and contains the identical chainId != 1 bug at line 967. Both contracts have been revoked as block number providers.

ContractAddressStatus
L1BlockOracleUpdater (exploited)0xb104d3a146f909d9d722005a5bdb17e570c88c6aRevoked
L1BlockOracleUpdater (multi-oracle)0xaE74643A86ca9544a41c266BC5BF2d26479f64E7Revoked

Multi-Oracle Authorization Status

OracleAddressAuthorized
Oracle (Curve)0x36F5B50D70df3D3E1c7E1BAf06c32119408Ef7D8No (revoked)
Oracle (Curve)0x000000009f42db5807378c374da13c54C856c29cNo (revoked)
Oracle (Curve)0x000000009271842F0D4Db92a7Ef5544D1F70bC1ANo (revoked)
Oracle (Pendle)0x16048a62aaEB91b922f1020469B7bA200c1c41E9No (revoked)
Oracle0x34D9e39c3B2F5BC2C973814531E8C8c9184Ed73ANo (revoked)

Key Addresses

EntityAddress
Exploiter0x595B8888858E2748dA23EB026Cac06eF1Bf9d497
Exploiter (fund consolidation)0xB40125d2e1b83A36Fde292f75922793e5f3F94fF
Arbitrum funder0x93900a94ff0db186c4b994911dd6f4c7f05ae49e
Base funder0x18Bead774f927Af586F86F6d054C269416E163DD
Votemarket (Arbitrum & Base)0x8c2c5A295450DDFf4CB360cA73FCCC12243D14D9
Oracle0x36F5B50D70df3D3E1c7E1BAf06c32119408Ef7D8
Verifier0x6095EBE7EbF2E0a912d6e293b00A6241a1A23dB3
LaPoste0xF0000058000021003E4754dCA700C766DE7601C2
CCIP OffRamp (Ethereum)0xdf615eF8D4C64d0ED8Fd7824BBEd2f6a10245aC9

Preliminary On-Chain Trace

The wallet used in the transactions appears to have been funded through a traceable chain originating from a KYC-required exchange.

HitBTC (KYC exchange)
  └→ Union Chain (0x963737c550e70ffe4d59464542a28604edb2ef9a), B2B payout service (unionchain.ai)
       └→ 0x595B8888 (exploiter, Ethereum mainnet)
            ├→ 0x93900a94 (Arbitrum funder, active since 2023)
            │    └→ funded by 0x995a09ed → 0xaa6b09ed (distribution wallets)
            └→ 0x18bead77 (Base funder, active since 2023)
  • Mar 5, 01:31:23: Union Chain sends 0.07 ETH to exploiter on Ethereum (0x380e536e...)
  • Mar 11, 05:32:11: Union Chain sends 0.11 ETH to exploiter on Ethereum (0x620ba906...)

Union Chain (0x963737c5...) is Etherscan-labeled and linked to unionchain.ai. The funding chain appears to originate from an address labeled on Etherscan as associated with HitBTC.

Timeline of Events (UTC)

All timestamps are derived from on-chain transaction data.

Preparation: March 5-11, 2026

Time (UTC)EventTransaction
Mar 5, 01:28:550.014 ETH from Arb funder 0x93900a94... → exploiter on Arbitrum0xedf2afc7...
Mar 5, 01:31:230.07 ETH from Union Chain 0x963737c5... → exploiter on Ethereum0x380e536e...
Mar 5, 01:35:150.014 ETH from Base funder 0x18bead77... → exploiter on Base0xeea30a61...
Mar 11, 05:32:110.11 ETH from Union Chain 0x963737c5... → exploiter on Ethereum0x620ba906...
Mar 11, 05:39:070.286 ETH from Arb funder 0x93900a94... → exploiter on Arbitrum0xe107abde...

Phase 1: Oracle Poisoning via L1 (March 12, 00:08-00:09)

Time (UTC)EventTransaction
00:08:59Send Message on Ethereum L1 to LaPoste → Arbitrum L1BlockOracleUpdater. Injects fabricated block data (block 99999999, epoch 1773273600).0xeab3c979...
00:09:35Send Message on Ethereum L1 to LaPoste → Base L1BlockOracleUpdater. Injects fabricated block data.0x03c0718a...

Phase 2: CCIP Delivery & Base Exploit (March 12, 00:23-00:28)

Time (UTC)EventTransaction
00:23:30CCIP transmit delivers the LaPoste message on Arbitrum. L1BlockUpdated event emitted: epoch 1773273600, block 99999999, timestamp 1773273700. Sender check bypassed due to chainId == 1.0xf6579655...
00:28:09CCIP message delivered on Base. Attacker executes the full exploit chain on Base in a single block (43242971): proof registration, vote data injection, and 4 claims on campaigns 82, 84, 85, 86. Stolen: USDC (~7,170), USDp (~960), CRV (~30,960).0xd2846418... 0xf683754a... 0x7b7a6321... 0xa7e9649e...

Phase 3: Proof Registration on Arbitrum (March 12, 00:39-00:45)

Time (UTC)EventTransaction
00:39:15Set Block Data on Verifier. Registers crafted RLP block header with attacker-controlled state root hash.0x739562cd...
00:39:19-00:41:0516 alternating Set Point Data + Set Account Data calls on Verifier. Registers fabricated gauge vote data for targeted campaigns.0x617e46f8...0xda88828b...
00:41:05-00:44:0950+ additional Set Point Data + Set Account Data pairs. Extends fabricated vote registrations across all 50 campaigns.(continuous batch)
00:44:09-00:45:4140+ Set Account Data calls. Final vote data registration for remaining campaigns.0xb518b97f...0xf974d9ea...

Phase 4: Reward Drain on Arbitrum (March 12, 00:45-00:50)

Time (UTC)EventTransaction
00:45:45-00:50:5150 Update Epoch + Claim pairs on Votemarket. Claims the reward allocations across all 50 Arbitrum campaigns. Each claim extracts the full campaign reward budget for epoch 1773273600.First: 0x692fc9e9... Last: 0x5bd35680...

Phase 5: Asset Bridging from Arbitrum (March 12, 00:51)

Time (UTC)EventTransaction
00:51:18-00:51:4916 Send Message calls from Arbitrum to LaPoste. Bridges stolen assets from Arbitrum to Ethereum via CCIP.0xd1c33208...0x1cf3cbe6...

Phase 6: CCIP Manual Execution on Ethereum (March 12, 01:51-01:58)

Time (UTC)EventTransaction
01:51:59-01:58:4712 Manually Execute calls on Ethereum CCIP OffRamp (0xdf615eF8...). Manually executes pending CCIP messages to receive bridged stolen assets on Ethereum L1.First: 0x73f79b8a... Last: 0x1bdd1559...

Phase 7: Asset Swaps ('Laundering') & Fund Consolidation (March 12, 04:20-11:39)

Time (UTC)ChainEventTransaction
00:28:09BaseStolen USDC, USDp, CRV swapped to WETH on Base DEXes immediately after claims(same block as claims)
04:20:11-05:22:59EthereumArbitrum stolen tokens swapped on Ethereum DEXes: Uniswap V3 (USDC, FXS, DOLA), SushiSwap (SPELL, ASF), Curve (OUSD/USDC, DOLA/sUSDS, WFRAX). Redeemed via Sky (USDS→DAI). All proceeds converted to WETH.30+ swap/approve txs
05:39:47-06:09:59EthereumProceeds transferred from 0x595B8888... to consolidation address 0xB40125d2e1b83A36Fde292f75922793e5f3F94fF0xeaf1ef1b...0x72dae56d...
07:36:57BaseBase WETH proceeds (~5.73 WETH) transferred to consolidation address 0xB40125d2...0xf8a150a3...
11:39:23EthereumConsolidation address unwraps 69.64 WETH to ETH on Ethereum0xedefabe8...

Incident Response & Mitigation

A technical investigation was initiated immediately upon detection of the incident. The analysis presented below reflects findings derived from on-chain transaction data and internal protocol review.

TimeEvent
Mar 12, 2026Incident detected and response initiated. Both L1BlockOracleUpdater contracts (0xb104d3a1... and 0xaE74643A...) revoked as authorized block number providers on all affected Oracles.

Phase 8: Second Attack Attempt (March 12, 14:13), Failed

The attacker attempted a second exploit from the consolidation address 0xB40125d2..., targeting the next epoch (March 19, 1773878400). Two new Send Message calls were sent to LaPoste targeting both Arbitrum and Base with fabricated block data (block 99999999, timestamp 1773878500). Both messages were successfully sent on Ethereum L1 but had no effect. The L1BlockOracleUpdater had already been revoked as an authorized block number provider on all Oracles, preventing any new fabricated block data from being written.

Time (UTC)EventTransaction
14:13:23Send Message on Ethereum L1 to LaPoste → Arbitrum L1BlockOracleUpdater (0xae74643a...). Blocked by revocation.0x06fc4d06...
14:13:59Send Message on Ethereum L1 to LaPoste → Base L1BlockOracleUpdater (0xae74643a...). Blocked by revocation.0x0d2febe2...

Current Status of Stolen Funds

All stolen assets were converted to ETH and consolidated at the attacker's address 0xB40125d2e1b83A36Fde292f75922793e5f3F94fF:

ChainAmountSource
Ethereum~69.8 ETHArbitrum stolen assets bridged, swapped, and unwrapped
Base~5.73 ETHBase stolen assets swapped to WETH and transferred
Total~75.5 ETH (~$160,000)

Remediation

  • Both vulnerable L1BlockOracleUpdater contracts have been revoked as authorized block number providers across all 5 affected Oracles.
  • The multi-oracle variant containing the identical bug was identified and revoked proactively.
  • The attacker's second exploit attempt (Phase 8) was fully neutralized by the revocation, confirming the effectiveness of the mitigation.
  • A corrected implementation addressing the sender validation logic is under development.
  • Only the March 12 epoch (1773273600) was exploited. All subsequent epochs are unaffected and will resume distributing rewards correctly.
  • Potential remediation options for affected campaign participants are currently under assessment.