This is a lower bound: only assets with reliable historical USD prices are counted, so the actual loss may be higher.
0xa1301596c77938cb31cbd282da79f6499f23cd8ffff5e609a77216ea1cf040a40xcdf14446f78ea7ebcaa62fdb0584e4d2e536b999Ethereum0x359cf536b1fd6248ebad1449e1b3727cab33a01dEthereumA 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.
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.0x359cf536b1fd6248ebad1449e1b3727cab33a01d selector 0x6cd50a67, which then calls connector applyState(bytes) (0x9bd15c9e).0x7bd736631afbe1d3795a94f60574f7fa0ae89347; two transient helper contracts are created (0xddf10e..., 0xfc99fa...) and self-destructed after execution.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.
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
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.
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"
}
}
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.
End-to-end adversary execution in one transaction:
TaraClient.finalizeBlocks with attacker-controlled validator update and signature tuple.totalWeight, then validates signatures/quorum against mutated state, and finalizes attacker-chosen root.0x6cd50a67; bridge triggers connector applyState(bytes) calls:
0x2b5ec5c4... (ETH path),0x950bcda6... (USDT path),0xff235ea7... (TARA path).0x00000000008892..., Uniswap V3 pool 0xc7bbec68..., UniV4 adapter 0x5745050e..., DPP clone 0x0ecef178...).0xdadb0d80178819f2319190d340ce9a924f783711.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:
0xcdf14446f78ea7ebcaa62fdb0584e4d2e536b9990x359cf536b1fd6248ebad1449e1b3727cab33a01dMeasured impact from collected balance/log artifacts:
0x7759b67c... at nonce 572.4.336484040293252284 (connector-path extraction)5,958,440,8441e50 minted into attacker path before swaps+7.381999992558813941 ETH (post gas and explicit 0.01 ETH builder payment included in net state delta accounting).0xa1301596c77938cb31cbd282da79f6499f23cd8ffff5e609a77216ea1cf040a4.0xcdf14446....finalizeBlocks replay trace showing successful path and recovered signer.0 to 0x7fffffff) for the same compact signature.0x34eae071... showing jump-to-0x0db3 before jump-to-0x0887 and associated SSTORE/SLOAD points.