All incidents

Tara Light Client Quorum-Check Ordering Bug Enables Forged Bridge Finalization and WETH Drain

Share
Feb 22, 2026 17:01 UTCAttackLoss: 1.14 WETHManually checked1 exploit txWindow: Atomic

Root Cause Analysis

Tara Light Client Quorum-Check Ordering Bug Enables Forged Bridge Finalization and WETH Drain

1. Incident Overview TL;DR

On Ethereum mainnet, transaction 0x2074d4f995bc4d009c25a40ea746be4e661d9a7a15fdfc9fdc9a419394986e60 (block 24513770) executes a deterministic ACT exploit against Tara bridge light-client integration and downstream DPP liquidity. The attacker-controlled transaction updates validator weights and then passes quorum checks inside the same finalizeBlocks(((uint256,bytes32,bytes32,bytes32,uint256),(address,int32)[])[],(bytes32,bytes32)[]) execution. This forged finalization sets a fake bridge root and unlocks bridge state application that mints TEST tokens into DPP pool 0x0ecef178f5831494b6275ce838eda09bb67fd869.

The root cause is strict ordering failure in the light-client implementation 0x34eae07195d83305a0be4786f2ab8705613c69c0: calldata-provided vote deltas are applied to validatorVoteCounts and totalWeight before quorum verification. The exploit then sells minted quote-side assets through DPP, drains WETH liquidity, unwraps WETH to ETH, and exits with net ETH profit after gas.

ACT framing is satisfied: the exploit path uses public contracts, public calldata formats, and public on-chain state only, with no privileged keys or governance permissions.

2. Key Background

Protocol context required to understand this incident:

  • Light-client entry: 0xcdf14446f78ea7ebcaa62fdb0584e4d2e536b999.
  • Light-client implementation: 0x34eae07195d83305a0be4786f2ab8705613c69c0.
  • Bridge apply proxy path: 0x359cf536b1fd6248ebad1449e1b3727cab33a01d -> 0x089f8b425e4ab63b46e1e88688c138e44fbddff6 -> state appliers 0xff235ea751964bba3887392de889a834a2bdfbde / 0xa134a9513589fa446f0a4da548a18488e38729b1.
  • Liquidity target: DPPAdvanced pool 0x0ecef178f5831494b6275ce838eda09bb67fd869.
  • Assets: TEST token 0x2f42b7d686ca3effc69778b6ed8493a7787b4d6e, WETH 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2.

Relevant storage model and selectors:

  • finalizeBlocks selector: 0x5d0d5734.
  • validatorVoteCounts mapping slot index: 8.
  • totalWeight storage slot index: 9.
  • finalizedBridgeRoots mapping slot index: 7.
  • Derived slot for validatorVoteCounts(0x7e5f4552091a69125d5dfcb7b8c2659029395bdf): 0x1d373a3e5853edae26cb3f8cbbdf6744bd2f1f679148aa7cf8cb59e6414d326e.
  • Derived slot for finalizedBridgeRoot(573): 0xfb63f75781a61ebcf1cdfe0e89d9459768093e285c1d9c6cbaf75faa636e558a.

3. Vulnerability Analysis & Root Cause Summary

This is an ATTACK-class logic bug, not a benign MEV arbitrage pattern. The invariant should be: quorum for a block finalization must be computed from the pre-existing validator set, not a validator set mutated by the same untrusted input payload. In the vulnerable flow, finalizeBlocks consumes (validator, int32 delta) pairs, updates validator weights and totalWeight, and only afterward computes/validates signer weight thresholds. Because of this order, the call can self-authorize by injecting a high weight (here int32.max) for a signer whose signature is supplied in the same call.

The exploit then sets forged finalized state (getFinalizedBridgeRoot(573)), calls bridge apply logic, mints 4e33 TEST into DPP, and sells quote-side liquidity for WETH. Net effect is measurable value extraction from protocol-integrated liquidity under an unauthorized finalized root.

Security principles violated:

  • Check-before-effect sequencing for consensus/quorum logic.
  • Trust-boundary separation between proposal payload and authorization state.
  • Non-circular authorization (state updates must not authorize themselves).

4. Detailed Root Cause Analysis

4.1 ACT Opportunity Definition

  • Pre-state block B: 24513769.
  • Adversary-crafted sequence b: single transaction 0x2074d4f995bc4d009c25a40ea746be4e661d9a7a15fdfc9fdc9a419394986e60.
  • Success predicate:
    • Monetary: attacker net ETH increases after fees.
    • Non-monetary: finalized bridge root is accepted under attacker-mutated quorum state.

The transaction is permissionless to submit and uses only public functions and public data. No privileged actor assumptions are required.

4.2 Code-Level Breakpoint (Victim Implementation)

Opcode evidence from the light-client implementation disassembly shows update-before-verification ordering.

0005c0 JUMPDEST
0005e2 PUSH2 0db3
0005e5 JUMP            ; enter validator-update loop first
...
000609 PUSH1 00
00060d PUSH1 09
00060f SLOAD           ; totalWeight read after update path
...
000660 PUSH2 0887
000663 JUMP            ; jump to signer/quorum routine
...
000887 JUMPDEST        ; signature/weight verification routine
...
000db3 JUMPDEST        ; validator update loop entry
...
000eb8 SIGNEXTEND      ; int32 delta handling from calldata
...
000f00 ... SSTORE      ; write validatorVoteCounts(slot8,address)
000f1e SSTORE          ; write totalWeight(slot9)
000f22 PUSH2 0db8
000f25 JUMP            ; loop continuation

This directly matches the claimed breakpoint: update loop (0xdb3) is reached before threshold and signer-weight checks (0x609, 0x887).

4.3 On-Chain Execution Evidence

Trace evidence for the seed transaction shows the exact malicious payload and downstream execution:

0xcDF14446...::finalizeBlocks(
  [((25384000, ..., 0xcfc74ddd..., 0xa5010456..., 573),
    [(0x7bD73663..., -2000000), (0x7E5F4552..., 2147483647)])],
  [(0xe834c996..., 0x1667be5c...)]
)
0x34EAe071...::finalizeBlocks(...) [delegatecall]
PRECOMPILES::ecrecover(...) -> 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf

State-change and bridge-apply evidence in the same trace:

@ 0xfb63f75781a61ebcf1cdfe0e89d9459768093e285c1d9c6cbaf75faa636e558a: 0 -> 0xa5010456...
0x359CF536...::6cd50a67(...)
0x089F8B42...::6cd50a67(...) [delegatecall]

Receipt and token-flow evidence confirm mint and extraction:

{
  "status": "0x1",
  "gasUsed": "0x20241e",
  "effectiveGasPrice": "0xa5df902",
  "contractAddress": "0x8cac44586a4779e9ebdd698f8158cfc7a2fe80b7"
}
{
  "erc20_balance_deltas": [
    {
      "token": "0x2f42b7d686ca3effc69778b6ed8493a7787b4d6e",
      "holder": "0x0ecef178f5831494b6275ce838eda09bb67fd869",
      "delta": "4000000000000000000000000000000000"
    }
  ],
  "native_balance_deltas": [
    {
      "address": "0x9c8624440d1ae80f173694e6a4f650e2418b8213",
      "delta_wei": "1141129020340209213"
    },
    {
      "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
      "delta_wei": "-1141488345067626941"
    }
  ]
}

4.4 Deterministic Arithmetic Checks

  • gasUsed = 0x20241e = 2,106,398.
  • effectiveGasPrice = 0x0a5df902 = 173,930,754 wei.
  • Fee = 366,367,392,364,092 wei.
  • Attacker gross ETH in from exploit path minus net balance delta equals fee exactly.

Weight/quorum arithmetic from storage diffs:

  • totalWeight before = 0x80182d65 = 2,149,068,133.
  • totalWeight after = 0xfff9a8e4 = 4,294,551,780.
  • Added signer weight after update = 0x7fffffff = 2,147,483,647.
  • Post-update majority threshold = 2,147,275,891.
  • Signer margin = 207,756.

This is sufficient to show self-authorization became possible only because update and verification happen in the same call in the wrong order.

5. Adversary Flow Analysis

Adversary-related accounts:

  • EOA 0x9c8624440d1ae80f173694e6a4f650e2418b8213: sender, gas payer, final ETH recipient.
  • Contract 0x8cac44586a4779e9ebdd698f8158cfc7a2fe80b7: created in exploit tx.
  • Contract 0x6dbb7c95ba397e8342777e068a1887418a42fbb4: in-tx runner that executes exploit sequence.

Victim-side candidates in the exploit path:

  • 0xcdf14446f78ea7ebcaa62fdb0584e4d2e536b999 (light-client entry).
  • 0x34eae07195d83305a0be4786f2ab8705613c69c0 (light-client implementation).
  • 0x359cf536b1fd6248ebad1449e1b3727cab33a01d (bridge connector proxy).
  • 0x0ecef178f5831494b6275ce838eda09bb67fd869 (DPPAdvanced pool).

Lifecycle stages from evidence:

  1. Adversary setup
    • Prior same-EOA contract creations: 0x2d9abc22... (block 24512117) and 0x9db1de9d... (block 24513681).
  2. Forged finalization + bridge apply
    • Tx 0x2074d4f9... injects vote deltas, finalizes forged root, executes bridge apply call 0x6cd50a67.
  3. Liquidity extraction + profit realization
    • Same tx performs DPP sellQuote, receives WETH, unwraps to ETH, and forwards value back to attacker EOA.

End-to-end exploit sequence is single-transaction and permissionless.

6. Impact & Losses

Measured losses/impact from canonical deltas:

  • WETH depletion from protocol-integrated liquidity: 1,141,488,345,067,626,941 wei (1.141488345067626941 WETH).
  • Attacker net ETH increase (after gas): 1,141,129,020,340,209,213 wei.
  • Test token minted into DPP pool via forged bridge state: 4,000,000,000,000,000,000,000,000,000,000,000 raw units.

Scope:

  • Consensus-like trust of bridge finalization is broken for the affected path.
  • Downstream integrator liquidity (DPPAdvanced) is directly drained as a consequence of forged finalized root acceptance.

7. References

Primary reproducible evidence:

  1. Seed tx metadata (0x2074d4f9...): /workspace/session/artifacts/collector/seed/1/0x2074d4f995bc4d009c25a40ea746be4e661d9a7a15fdfc9fdc9a419394986e60/metadata.json
  2. Full execution trace (cast -vvvvv): /workspace/session/artifacts/collector/iter_1/tx/1/0x2074d4f995bc4d009c25a40ea746be4e661d9a7a15fdfc9fdc9a419394986e60/trace.cast.requery.log
  3. Canonical receipt: /workspace/session/artifacts/collector/iter_1/tx/1/0x2074d4f995bc4d009c25a40ea746be4e661d9a7a15fdfc9fdc9a419394986e60/receipt.requery.json
  4. Native/ERC20 balance deltas: /workspace/session/artifacts/collector/iter_1/tx/1/0x2074d4f995bc4d009c25a40ea746be4e661d9a7a15fdfc9fdc9a419394986e60/balance_diff.requery.json
  5. Light-client implementation disassembly: /workspace/session/artifacts/collector/iter_1/contract/1/0x34eae07195d83305a0be4786f2ab8705613c69c0/disassemble/runtime-disassembled.asm
  6. Slot derivation notes: /workspace/session/artifacts/auditor/iter_1/slot_derivations.txt
  7. Numeric consistency checks: /workspace/session/artifacts/auditor/iter_1/numeric_checks.txt

Incident-relevant transactions (complete set from root cause artifact):

  • Related setup: 0x2d9abc22d86f2097cc0a43fcfbc84525c31e08fb20fb692bcd146c798888ba63
  • Related setup: 0x9db1de9d9af98286f952ef3638a4d8034d154d5eca11049ff08c4ccd828c9e26
  • Adversary-crafted exploit: 0x2074d4f995bc4d009c25a40ea746be4e661d9a7a15fdfc9fdc9a419394986e60