Skip to navigation

Threat reportVulnerabilityTL-2026-4903

zkLink Nova bridge exploit (~$780K): uncleared transient hash in Arbitrator.claimMessage() enables forged batch root and escrow drain

highMONITORING

On 2026-10-28 22:21 UTC a single Ethereum transaction drained zkLink Nova's Ethereum escrows of 22.43 ETH and 11 ERC-20 tokens (about $780K depending on the pricing source). The attacker abused Arbitrator.claimMessage(), which runs a caller-supplied target and calldata and never clears its transient finalizeMessageHash slot, together with the publicly callable SyncL2TxHashRelayer, to install a forged batch root.

Key facts for TL-2026-4903

IdentifiersTL-2026-4903
Also known aszkLink Nova bridge hack, zkLink Nova forged batch root exploit
SeverityHIGH
Exploitation statusExploited in the wild
Affected productszkLink zkLink Nova bridge (Arbitrator, EthereumGateway, SyncL2TxHashRelayer, Ethereum escrow, L1ERC20Bridge)
Weaknesses (CWE)CWE-863, CWE-459, CWE-749
MITRE ATT&CK techniquesT1190 Exploit Public-Facing Application, T1565 Data Manipulation, T1587.004 Exploits, T1657 Financial Theft
MotivationFINANCIAL
Target sectorsfinance, cryptocurrency, defi
Target regionsGlobal
Detection rules9 (1 shown free)
Sources8 cited sources

Detection coverage for TL-2026-4903

As of 2026-10-31, Threadlinqs Intelligence publishes 9 detection rule(s) for TL-2026-4903 across Splunk SPL, Microsoft KQL and Sigma, covering 7 indicator(s) of compromise. The whole corpus is readable without an account. Every threat comes with one complete detection in Splunk SPL, Microsoft KQL and Sigma, free for everyone; a free account adds daily TL Creds to unlock the rest. Paid plans add a larger daily allowance, correlation and the MCP server. Threadlinqs MCP server · View plans.

Free detection: zkLink Arbitrator Stale finalizeMessageHash Reuse — Forged Batch Root

Per-transaction detection of the TL-2026-4903 exploit core: the Arbitrator relays syncBatchRoot to a gateway while claimMessage calls outnumber genuine receiveMessage calls, meaning a stale transient finalizeMessageHash was reused. Also hits the known attacker addresses and the exploit transaction hash.

  • Languages: Splunk SPL, Microsoft KQL, Sigma
  • ATT&CK: T1190, T1211, T1565, T1565.001, T1565.002, T1068
  • Data sources: ethereum_traces (index=blockchain sourcetype=ethereum:traces)
  • Severity: critical
  • Confidence: high

Splunk SPL

index=blockchain sourcetype="ethereum:traces" chain="ethereum" earliest=-24h
```Flag transactions where the zkLink Arbitrator relays syncBatchRoot with more claimMessage calls than genuine receiveMessage calls (stale finalizeMessageHash reuse, TL-2026-4903)```
| eval from_a=lower(from_address), to_a=lower(to_address)
| eval is_claim=if(to_a="0x1ee09a2caa0813a5183f90f5a6d0e4871f4c6002" AND method_name="claimMessage",1,0)
| eval is_root=if(from_a="0x1ee09a2caa0813a5183f90f5a6d0e4871f4c6002" AND method_name="syncBatchRoot",1,0)
| eval is_recv=if(method_name="receiveMessage",1,0)
| eval ioc_hit=if(in(from_a,"0xaca0655a11200a80d33d0e48786317304cde5718","0xd5f162b68a0281686e8dc76db8d67d2f3e6aff07","0xdab137f390df77caa97fd492540e973fd5e2f8c8") OR lower(tx_hash)="0x4f3c23e75b9134e8cae5a462550daad42fbbc19242567fcc34c0a035e297462c",1,0)
| stats sum(is_claim) as claim_calls sum(is_root) as root_calls sum(is_recv) as receive_calls max(ioc_hit) as ioc_hit min(_time) as first_seen values(from_a) as callers by tx_hash block_number
| where (root_calls>=1 AND claim_calls>receive_calls) OR ioc_hit=1
| eval first_seen=strftime(first_seen,"%Y-%m-%d %H:%M:%S")
| table first_seen tx_hash block_number callers claim_calls root_calls receive_calls ioc_hit

Microsoft KQL

let arbitrator = "0x1ee09a2caa0813a5183f90f5a6d0e4871f4c6002";
let ioc_addrs = dynamic(["0xaca0655a11200a80d33d0e48786317304cde5718","0xd5f162b68a0281686e8dc76db8d67d2f3e6aff07","0xdab137f390df77caa97fd492540e973fd5e2f8c8"]);
EthereumTraces_CL
| where TimeGenerated > ago(24h) and chain == "ethereum"
| extend from_a = tolower(from_address), to_a = tolower(to_address)
| summarize claim_calls = countif(to_a == arbitrator and method_name == "claimMessage"),
            root_calls = countif(from_a == arbitrator and method_name == "syncBatchRoot"),
            receive_calls = countif(method_name == "receiveMessage"),
            ioc_hit = max(iff(from_a in (ioc_addrs) or tolower(tx_hash) == "0x4f3c23e75b9134e8cae5a462550daad42fbbc19242567fcc34c0a035e297462c", 1, 0)),
            first_seen = min(TimeGenerated), callers = make_set(from_a) by tx_hash, block_number
| where (root_calls >= 1 and claim_calls > receive_calls) or ioc_hit == 1
| project first_seen, tx_hash, block_number, callers, claim_calls, root_calls, receive_calls, ioc_hit

Sigma

title: zkLink Arbitrator syncBatchRoot Relayed Without receiveMessage
id: 3b8e1c52-6f0a-4d7b-9a41-2c5d8e7f1a03
status: experimental
description: Detects the zkLink Nova Arbitrator invoking syncBatchRoot on a gateway through claimMessage, the forged batch root installation of TL-2026-4903. Transaction-level correlation of claimMessage versus receiveMessage counts is done in the SPL and KQL forms; this rule is the per-trace pre-filter.
references:
  - https://dev.to/pandasecurity/zklink-nova-exploit-a-stale-transient-hash-forged-a-root-oji
  - https://intel.threadlinqs.com
author: AII-Detector — ThreadLinqs Intelligence
date: 2026-10-31
tags:
  - attack.initial-access
  - attack.t1190
  - attack.defense-evasion
  - attack.t1211
  - attack.impact
  - attack.t1565.001
  - attack.t1565.002
  - attack.privilege-escalation
  - attack.t1068
logsource:
  product: ethereum
  service: traces
detection:
  selection_arb:
    from_address:
      - '0x1ee09a2caa0813a5183f90f5a6d0e4871f4c6002'
    method_name: 'syncBatchRoot'
  selection_ioc:
    from_address:
      - '0xaca0655a11200a80d33d0e48786317304cde5718'
      - '0xd5f162b68a0281686e8dc76db8d67d2f3e6aff07'
      - '0xdab137f390df77caa97fd492540e973fd5e2f8c8'
  condition: selection_arb or selection_ioc
falsepositives:
  - Legitimate zkLink Arbitrator relays of syncBatchRoot following a canonical bridge receiveMessage
  - Contract upgrade or migration testing on forks
level: high

Known false positives:

  • Legitimate Arbitrator syncBatchRoot relays that follow a canonical bridge receiveMessage in the same transaction
  • Forked-mainnet exploit replays by researchers

Tuning notes: Verify the trace ETL emits receiveMessage frames from canonical bridges; if it only emits top-level calls, count the bridge message events instead. Keep the Arbitrator address list current after the 2026-10-29 patch redeploys. Assumes a blockchain-ETL feed (node debug traces, decoded logs, transactions) with fields chain, tx_hash, block_number, from_address, to_address, method_name, inner_method_name, inner_target, event_name, token_address, value_eth; map names to your schema. KQL uses custom tables EthereumTraces_CL, EthereumLogs_CL, EthereumTransactions_CL.

8 more detection rules (Splunk SPL, Microsoft KQL, Sigma) · unlock with TL Creds. Sign up free to unlock the detection rules or query them with the Threadlinqs MCP server (Purple)
  • zkLink Arbitrator Multiple claimMessage Calls in One Transaction · unlock with TL Creds
  • zkLink Forged Batch Root Followed by Escrow Outflow in Same Transaction · unlock with TL Creds
  • zkLink Follow-On Forged Batch Root Attempts on Secondary Chains · unlock with TL Creds
  • zkLink claimMessage Wrapping syncBatchRoot (Forged Batch Root Mechanism) · unlock with TL Creds
  • zkLink Nova Exploit Transaction and Victim Contract Interaction · unlock with TL Creds
  • zkLink Exploit Contract Deployment and Staging by Attacker EOA · unlock with TL Creds
  • zkLink Escrow Multi-Token Drain in One Transaction · unlock with TL Creds
  • zkLink Exploit Actor Address Activity Across Chains · unlock with TL Creds

Indicators of compromise for TL-2026-4903

As of 2026-10-31, Threadlinqs Intelligence tracks 7 indicators of compromise for TL-2026-4903.

7 indicators of compromise · unlock with TL Creds. Compare plans

How zkLink Nova bridge exploit (~$780K) works

zkLink Nova is an aggregated Layer 3 zkEVM that uses an Arbitrator contract on Ethereum to relay sync hashes and batch roots between its primary chain and secondary-chain gateways (Linea, Optimism, Base, Blast, Mantle and others). Per zkLink documentation, the SyncL2TxHashRelayer periodically triggers secondary-chain contracts to send sync hashes through canonical bridges, the Arbitrator forwards them to the primary-chain gateway, and the batch root returns the same way to enable withdrawals.

The reported root cause (DEV Community analysis by panda-security; SlowMist as quoted by trade press) is two flaws in Arbitrator.claimMessage(). First, the function executes a caller-supplied target and calldata as the Arbitrator, and gateways trust msg.sender == Arbitrator. Second, the transient-storage validation hash finalizeMessageHash is never cleared, so once a genuine message arms it, it stays valid for later claims with matching parameters in the same transaction.

Exploit chain as reported: (1) the attacker called the publicly callable SyncL2TxHashRelayer with a legitimate pending Linea message, so the Linea bridge verified it and finalizeMessageHash was set; (2) in the same transaction the attacker called the relayer again, setting the canonical message service to EthereumGateway with calldata wrapping syncBatchRoot(116409, attackerChosenRoot, 0), which the gateway accepted because msg.sender was the Arbitrator; (3) EthereumGateway never called receiveMessage, so the slot stayed uncleared and the stale hash matched the recomputed one; (4) the attacker submitted 12 permissionless withdrawal proofs against the forged root and drained the escrows to their own address. Blockaid reported that a new batch root was recorded before the withdrawal events in the same transaction, leaving about 0.001 ETH in the ETH escrow.

The drain was 22.43 ETH plus pufETH 245.7379, USDC 18,113.45, ezETH 12.5693, rsETH 6.8665, STONE 6.2998, USDT 3,360.90, mstETH 2.6372, mswETH 2.4826, rswETH 0.5, wstETH 0.4660 and WBTC 0.1736. Valuations range from $743K to $805K; BlockSec Phalcon reported about $780K, SlowMist $783.1K, Blockaid about $786K, and Hokanews $778,625.84. Follow-on attacks were reported on Optimism, Base, Blast and Mantle; Parapet Labs attributed a second wave (about 24.76 ETH plus tokens, from 07:16 UTC on 2026-10-29) to a different actor. Secondary-chain pauses blocked deposits but not withdrawal finalization. zkLink suspended block production, patched the contracts and disabled withdrawals at about 13:08 UTC on 2026-10-29, and offered a 20% white-hat bounty with no further action if funds are returned. No CVE has been assigned. The SlowMist original could not be fetched (HTTP 403), so SlowMist statements here come from secondary reporting.

MITRE ATT&CK techniques by tactic:

Initial Access

T1190 Exploit Public-Facing Application

Impact

T1565 Data Manipulation; T1657 Financial Theft

Resource Development

T1587.004 Exploits

Remediation for zkLink Nova bridge exploit (~$780K)

Patches

  • zkLink patched the affected contracts on 2026-10-29; clear the transient slot after validation with tstore(slot, 0)

Immediate actions

  • Pause bridge withdrawal finalization on every connected chain, not only deposits
  • Monitor the attacker EOA 0xaca0655a11200a80d33d0e48786317304cde5718 and attack contract 0xd5f162b68a0281686e8dc76db8d67d2f3e6aff07 and block or flag exposure to funds from them
  • Alert on SyncL2TxHashRelayer calls that carry more than one message in a single transaction and on syncBatchRoot calls from the Arbitrator that were not preceded by a receiveMessage from the canonical bridge

Workarounds

  • Keep withdrawals disabled on all chains until patched contracts are verified

Longer-term hardening

  • Pin the canonical message service per gateway and never accept caller-chosen call targets in the Arbitrator
  • Use explicit allowlists for privileged call targets and function selectors
  • Run validation checks before effects and add multi-call fuzz tests within a single transaction
  • Treat permissionless relayers as public entry points and review them as such
  • Extend emergency pause coverage to withdrawal finalization

Affected and fixed versions

  • zkLink — zkLink Nova bridge (Arbitrator, EthereumGateway, SyncL2TxHashRelayer, Ethereum escrow, L1ERC20Bridge)
    Vulnerable versions: Contracts deployed before the 2026-10-29 patch
    Fixed in: Contracts patched by zkLink on 2026-10-29

Timeline of zkLink Nova bridge exploit (~$780K)

  • Security firms (BlockSec Phalcon, SlowMist, Blockaid) flag the drain the same evening; Unchained reports a security alert at 10:24 p.m. ET.
  • At 22:21:35 UTC (Ethereum block 26,294,188) a single transaction, 0x4f3c23e75b9134e8cae5a462550daad42fbbc19242567fcc34c0a035e297462c, arms finalizeMessageHash via SyncL2TxHashRelayer, installs a forged batch root for batch 116409 and finalizes 12 withdrawals draining 22.43 ETH and 11 ERC-20 tokens.
  • zkLink offers a 20% white-hat bounty and says no further action will be pursued if funds are returned; public technical write-ups and press coverage appear.
  • At about 13:08 UTC zkLink suspends block production, patches the contracts and disables withdrawals.
  • At about 09:06 UTC zkLink publishes a statement confirming an ongoing exploit on Ethereum and Optimism.
  • From about 07:16 UTC a second wave on L2 chains by a different actor (per Parapet Labs) extracts about 24.76 ETH plus tokens; similar attacks are reported on Optimism, Base, Blast and Mantle.

Sources cited for zkLink Nova bridge exploit (~$780K)

Drafted by the Threadlinqs research pipeline from 8 sources; published ; last updated —.

Threadlinqs Intelligence — Real-Time Threat Detection Platform

[ 0 threats ] [ 0 det ] [ CRIT: 0 ] [ HIGH: 0 ]
// threat_feed
$ sort --newest
Showing all threats

Live intelligence console

Threat level

Latest Threats