All incidents

TaraClient finalizeBlocks Quorum-Bypass via In-Tx Validator Set Mutation

Share
Feb 22, 2026 16:27 UTCAttackLoss: 4.34 ETH, 5,958.44 USDT +1 moreManually checked1 exploit txWindow: Atomic
Estimated Impact
4.34 ETH, 5,958.44 USDT +1 more
Label
Attack
Exploit Tx
1
Addresses
2
Attack Window
Atomic
Feb 22, 2026 16:27 UTC → Feb 22, 2026 16:27 UTC

Exploit Transactions

TX 1Ethereum
0xa1301596c77938cb31cbd282da79f6499f23cd8ffff5e609a77216ea1cf040a4
Feb 22, 2026 16:27 UTCExplorer

Victim Addresses

0xcdf14446f78ea7ebcaa62fdb0584e4d2e536b999Ethereum
0x359cf536b1fd6248ebad1449e1b3727cab33a01dEthereum

Loss Breakdown

4.34ETH
5,958.44USDT
100,000,000,000,000,000,000,000,000,000,000TARA

Similar Incidents

Root Cause Analysis

TaraClient finalizeBlocks Quorum-Bypass via In-Tx Validator Set Mutation

1. Incident Overview TL;DR

A single Ethereum mainnet transaction (0xa1301596c77938cb31cbd282da79f6499f23cd8ffff5e609a77216ea1cf040a4, block 24513601) executed a full exploit chain against TaraClient/Tara Bridge: validator-set takeover, malicious block finalization, connector state application, swaps, and ETH profit extraction.

The root cause is a code-ordering flaw in finalizeBlocks on TaraClient implementation 0x34eae07195d83305a0be4786f2ab8705613c69c0 (proxy 0xcdf14446f78ea7ebcaa62fdb0584e4d2e536b999). Attacker-controlled validator updates are applied before quorum/signature-weight validation, so authorization is checked against in-transaction mutated state rather than the pre-existing validator set.

This is an ACT-class exploit (is_act=true): an unprivileged EOA can submit the same class of payload and realize profit without privileged keys.

2. Key Background

  • TaraClient stores validator voting weights in validatorVoteCounts (mapping slot base 8) and aggregate voting power in totalWeight (slot 9).
  • finalizeBlocks selector is 0x5d0d5734; signature-weight helper is getSignaturesWeight(bytes32,(bytes32,bytes32)[]) selector 0x97f8e2f0.
  • Bridge state application is invoked through bridge proxy 0x359cf536b1fd6248ebad1449e1b3727cab33a01d selector 0x6cd50a67, which then calls connector applyState(bytes) (0x9bd15c9e).
  • In the seed exploit transaction, the attacker EOA is 0x7bd736631afbe1d3795a94f60574f7fa0ae89347; two transient helper contracts are created (0xddf10e..., 0xfc99fa...) and self-destructed after execution.

3. Vulnerability Analysis & Root Cause Summary

Root-cause category is ATTACK. The broken invariant is: signature quorum for block finalization must be computed from the validator set that existed before applying any validator updates in that same call. In the vulnerable flow, the contract first writes attacker-supplied validator updates and totalWeight, then computes signature weight/quorum.

Disassembly evidence shows finalizeBlocks jumps to update routine 0x0db3 before jumping to signature-weight routine 0x0887. The update routine performs SSTORE to the validator mapping and totalWeight; the signature routine later does SLOAD from the validator mapping for recovered signers. As a result, a signature that has zero pre-state voting power is counted as high-weight after attacker-controlled writes execute.

This enables unauthorized finalization of attacker-chosen bridge roots and downstream bridge-state execution, violating finality/security assumptions and enabling asset extraction.

4. Detailed Root Cause Analysis

4.1 Exploit pre-state and payload

Before the exploit transaction:

  • totalWeight = 1,584,486.
  • validatorVoteCounts[0x7bd736631afbe1d3795a94f60574f7fa0ae89347] = 0.

The attacker-crafted finalizeBlocks payload includes a validator update assigning weight 2147483647 to the attacker address and uses one compact signature tuple.

Seed finalize payload (decoded):
validator update: (0x7bd736631afbe1d3795a94f60574f7fa0ae89347, 2147483647)
nonce: 572
new_hash: 0x966ab46259230d719c7ffc5a73688b23f230f16521b11115efa5eb544b115222
bridge_root: 0x7759b67c3728c3cf1d79dc2f15b42ea903c349029b8bd189406abc5c5198b433

4.2 Code-level breakpoint (ordering bug)

cast_disassembly.txt for implementation 0x34ea... shows the critical execution order:

000005e2: PUSH2 0x0db3
000005e5: JUMP            ; enter validator update routine first
...
00000660: PUSH2 0x0887
00000663: JUMP            ; enter signature-weight/quorum routine after updates

00000f02: SSTORE          ; write validatorVoteCounts[...] (mapping slot base 8)
00000f1e: SSTORE          ; write totalWeight (slot 9)
...
00000a5d: SLOAD           ; read validatorVoteCounts[...] during signature weighting

This establishes the invariant break at code level: authorization depends on state that the same attacker-controlled call has just mutated.

4.3 Independent runtime/state confirmation

Signature-weight checks around inclusion prove the effect is not theoretical:

preblock_getSignaturesWeight(...seed_signature)  = 0x0
postblock_getSignaturesWeight(...seed_signature) = 0x7fffffff

Negative checks also prove quorum is based on mutated totalWeight:

empty signatures revert -> custom error 0xb7842ce0 arg0=0x400c16b3 arg1=0x0
low weight update revert -> custom error 0xb7842ce0 arg0=0x000c16b4 arg1=0x0

Slot-level state diff for 0xcdf... in the seed tx confirms in-call mutation:

{
  "validator_slot": {
    "slot": "0xd112448c754d9230d04a6b39cef14b6a8307790cdd38c7db3617572e79e370c0",
    "value": "0x000000000000000000000000000000000000000000000000000000007fffffff"
  },
  "totalWeight_slot_9": {
    "before": "0x0000000000000000000000000000000000000000000000000000000000182d66",
    "after": "0x0000000000000000000000000000000000000000000000000000000080182d65"
  }
}

4.4 Full exploit consequence

After unauthorized finalization, execution immediately proceeds through bridge state application (0x359c...::0x6cd50a67) and connector applyState(bytes) calls to release assets into attacker runtime logic, followed by swaps and ETH extraction to the attacker EOA.

5. Adversary Flow Analysis

End-to-end adversary execution in one transaction:

  1. Deploy helper/orchestrator contracts.
  2. Call TaraClient.finalizeBlocks with attacker-controlled validator update and signature tuple.
  3. Contract applies validator update and inflated totalWeight, then validates signatures/quorum against mutated state, and finalizes attacker-chosen root.
  4. Call bridge entrypoint 0x6cd50a67; bridge triggers connector applyState(bytes) calls:
    • 0x2b5ec5c4... (ETH path),
    • 0x950bcda6... (USDT path),
    • 0xff235ea7... (TARA path).
  5. Route extracted assets through swap venues (0x00000000008892..., Uniswap V3 pool 0xc7bbec68..., UniV4 adapter 0x5745050e..., DPP clone 0x0ecef178...).
  6. Pay 0.01 ETH to 0xdadb0d80178819f2319190d340ce9a924f783711.
  7. Self-destruct helper contracts and return residual ETH to attacker EOA.

Representative call-tree excerpt:

CALL      ... -> 0xcdf14446... selector 0x5d0d5734
DELEGATE  0xcdf14446... -> 0x34eae071... selector 0x5d0d5734
CALL      ... -> 0x359cf536... selector 0x6cd50a67
CALL      0x359cf536... -> 0x2b5ec5c4... selector 0x9bd15c9e
CALL      0x359cf536... -> 0x950bcda6... selector 0x9bd15c9e
CALL      0x359cf536... -> 0xff235ea7... selector 0x9bd15c9e
SELFDESTRUCT 0xfc99fa4b... -> 0xddf10e09...
SELFDESTRUCT 0xddf10e09... -> 0x7bd73663...

Adversary-related accounts identified:

  • 0x7bd736631afbe1d3795a94f60574f7fa0ae89347 (EOA sender and net recipient)
  • 0xddf10e090791369024cfa51c3df1192bfeda3eae (created helper)
  • 0xfc99fa4b30bdb2e3da90706882a24759307b0343 (runtime executor)

Victim protocol components:

  • TaraClient proxy 0xcdf14446f78ea7ebcaa62fdb0584e4d2e536b999
  • Bridge proxy 0x359cf536b1fd6248ebad1449e1b3727cab33a01d

6. Impact & Losses

Measured impact from collected balance/log artifacts:

  • Unauthorized consensus/finality break: attacker finalized bridge root 0x7759b67c... at nonce 572.
  • Unauthorized bridge-state application triggered connector transfers and token mint/flows.
  • Reported extracted amounts:
    • ETH: 4.336484040293252284 (connector-path extraction)
    • USDT: 5,958,440,844
    • TARA: 1e50 minted into attacker path before swaps
  • Net attacker EOA native delta in seed tx: +7.381999992558813941 ETH (post gas and explicit 0.01 ETH builder payment included in net state delta accounting).

7. References

  1. Seed transaction metadata and tx payload: 0xa1301596c77938cb31cbd282da79f6499f23cd8ffff5e609a77216ea1cf040a4.
  2. Slot-level state diff for validator/weight mutation on TaraClient proxy 0xcdf14446....
  3. finalizeBlocks replay trace showing successful path and recovered signer.
  4. Negative replay traces showing quorum reverts for empty signatures and low-weight mutation.
  5. Signature-weight pre/post checks (0 to 0x7fffffff) for the same compact signature.
  6. Disassembly of implementation 0x34eae071... showing jump-to-0x0db3 before jump-to-0x0887 and associated SSTORE/SLOAD points.
  7. Seed call-tree and receipt logs showing bridge/connector execution and extraction flow.
  8. Seed balance-diff artifact showing final ETH deltas and builder payment account.