An incident report from Tari contributors:
On September 6, 2026 at 14:42:53 UTC, an unknown actor began exploiting a consensus flaw in Tari’s C29 (Cuckaroo29) proof-of-work lane. The first forged block appeared at height 339,109. Vulnerable nodes accepted it without complaint, because it carried a fully valid proof under the rules the network actually enforced. More followed, 359 of them by September 18, at a cadence no honest fleet of C29 miners could ever sustain. The lane’s difficulty, which had sat near 80,000 for months, was driven to hundreds of thousands and spiked past six million at the peak. The network’s difficulty algorithm chased a miner that wasn’t mining honestly.
Sixteen days later, at 02:12:33 UTC on September 22, block 350,000 activated the hard fork that closed the flaw.
What follows is a detailed record of the incident, hour by hour, and how it was handled by contributors.
The Bug
Tari’s four-lane design
Tari runs four proof-of-work algorithms in parallel — SHA3X, RandomXT (Tari-only RandomX), RandomXM (RandomX merge-mined with Monero), and C29 (Cuckaroo29). A block is valid in whichever lane found it, and chain strength is the geometric mean of the accumulated difficulty across all lanes. No single lane can carry the longest chain on its own. That design decision is the main reason this incident never became a chain split.
The C29 verifier never enforced bipartiteness
C29 is Tari’s port of Cuckaroo, the memory-hard proof-of-work built around a simple idea: build a graph whose edges are derived from the block header, then prove you found a cycle in it. Finding a 42-cycle in a 2^29-node Cuckoo graph is the intended work — it needs the memory and time that make the algorithm ASIC-resistant and costed per solution.
There is one property that makes Cuckaroo’s cycle-finding genuinely hard: the graph is bipartite. Every edge connects a node in one partition to a node in the other, and a valid cycle must alternate sides. That partition structure is what forces a solver to work with an edge space split into two disjoint 2^29-node halves, and it is the backbone of the algorithm’s security.
Tari’s pre-fork C29 verifier never enforced it. Both endpoints of every edge were derived from a single 64-bit siphash output (u = edge & mask, v = (edge >> 32) & mask), landing in one shared, merged node namespace, and the “cycle” was verified as a generic closed walk in that single namespace. The checks the verifier did keep — XOR-sum of endpoints, degree-2 on every node, a full walk returning to its start — are all satisfied by a merged-namespace “chain” (a0,a1), (a1,a2), …, (aN,a0) of the kind that cannot exist in a true bipartite Cuckaroo graph. With the partitions collapsed, the effective graph is half the nodes, denser, and free of the alternation constraint that gives the algorithm its memory-hardness. Finding valid 42-edge proofs dropped to a small fraction of the intended cost — which is exactly what an attacker needs to mine a lane far faster than its honest hashrate allows.
The post-fork verifier is a port of Grin’s ref_verify, in which index parity is the partition and the walk must alternate sides. The legacy verifier is retained below the activation height deliberately — every historical C29 block on every network was accepted under it, and changing it would invalidate that history.
C29 had been live on mainnet since January 19, 2026 (height 183,462) — roughly seven and a half months of honest mining before someone worked out what the verifier was actually checking.
Why this took a hard fork
This was not something a soft upgrade could fix. The flaw sits in consensus validation: a node cannot be configured out of accepting blocks it is programmed to consider valid, and blocks below the activation height must remain valid under the rules that produced them. Every historical C29 block was accepted under the legacy verifier, and retroactively invalidating them would fork the chain. So the legacy verifier stays in place below the fork, the bipartite verifier takes over at and above it, and the two rulesets are separated by a fixed activation height. That is what a hard fork is for.
The Timeline
September 6 — the first forged block
14:42:53 UTC, height 339,109. First forged block, mined on the C29 lane. Every block below it is genuine. The attacker’s blocks claimed the lane’s current difficulty (114,174 at the first one, already climbing from the ~80,000 baseline) — the flaw meant they could satisfy it for almost nothing, and the LWMA difficulty algorithm just kept repricing the lane upward.
Over the next twelve days the attacker mined in bursts: 20+ blocks in a row at times, individual blocks seconds apart, resulting in a lane difficulty that had nothing to do with the lane’s honest hashrate. It took fewer than 100 fast blocks to take the C29 difficulty from network-stable into the millions. Honest C29 miners were being priced out of their own lane.
September 18 — the alarm
At 02:58 UTC on September 18, the vulnerability was found and reported by momo — directly to Naveen and through GitHub’s private security advisory process. The team confirmed the finding and set to work on the fix, then opened the incident-response channel at 15:19 UTC.
15:19 UTC. The incident-response channel is opened. Within minutes, the situation is on the table:
The team confirms a vulnerability in the C29 implementation that allows proofs to be produced far more cheaply than intended. Difficulty has already risen to compensate, and a hot-fix hard fork is planned. The network is still secure: proof of work is still being performed, and the other algorithms are unaffected.
359 forged blocks so far, earliest at 339,109.
A blast-radius snapshot over the last 10,000 blocks shows the C29 lane dominated by a small set of pools — Kryptex (2,018 blocks), untagged miners (328), LuckyPool (242), and a direct C29 miner (3). Every one of them needs to be reached directly.
The issue had already been flagged publicly, which limited the time available to respond.
16:19 UTC. The fix is already made, but it requires a hard fork, and exchanges need lead time to upgrade.
18:21 UTC. The plan is set: hard fork at height 350,000, roughly 72 hours out. Exchanges are notified once the build is available.
September 19 — the build, the test, the release
02:01 UTC. Testing of the difficulty-algorithm penalty proposed for the same fork fails on Esmeralda — mined blocks are repeatedly reported by peers as below minimum difficulty, triggering ban waves and rolled-back nodes. The penalty is deferred; the 45-block difficulty window ships, which also helps the C29 difficulty recover faster after the fork.
05:13–06:38 UTC. Builds complete; v5.7.0-pre.10.
15:03 UTC. Exchanges and the major C29 pools are notified. One key operator upgrades within hours. Rollout begins.
15:25 UTC. First network census: 2,255 reachable nodes — 29 on pre.10 (1.3%). The bulk of the fleet runs 5.4.0 (90.6%). The TU release will carry most of the conversion.
September 20–21 — the long weekend
September 20. A wave of difficulty-related bans is reported after an upgrade. Seed nodes and team nodes check out healthy; the bans trace to peers claiming higher difficulty without sending headers. A non-event — but a reminder that every node matters during a fork rollout.
September 21, 11:00 UTC. The TU release rolls out; within hours, 60% of the fleet is upgraded.
16:13 UTC. 558 nodes on pre.10 (23.7%) — up from 29. The plateau breaks; the 5.4.0 fleet is converting.
01:57 UTC, September 22. 1,290 nodes on pre.10 (57.1%), 5.4.0 down to 34.2%. Thirteen blocks to go.
In the final hours the attacker escalates sharply — mining nearly every other block at a 2–4 minute cadence.
September 22 — the fork
02:12:33 UTC. Block 350,000 — mined by DxPool on the SHA3X lane — activates the fork. 663b7254df69989b33cec8325815631e2b455f7252c230976f1b50dc8daced47
The first minutes are not clean. Three of thirteen seed nodes are still on the previous build; the main explorer briefly shows a C29 block at 350,001 while the rest of the network shows SHA3X. For a few minutes it looks like the fork has split. It hasn’t: the seeds roll over, the explorer’s node is on the old build, and its UI still reports the old version. There is no reorg.
02:26 UTC. First post-fork C29 block, height 350,003.
The 45-block window is visible immediately in the difficulty prints.
Within half an hour of the fork the C29 lane has its first honest block, and the RandomX lanes catch up within the hour. With the attacker’s cadence gone, the response is closed out as fixed — pending the first C29, RXT and RXM blocks, which all land.
Later that day. The fix merges to development, and the verification tooling goes public.
The Response
The fork was set for height 350,000, roughly three days after the response began. Major miners and node providers were provided with an advanced build ahead of the fork to prepare for it, ensuring enough of the network was moved over to complete the transition without risking user funds, and without tipping off anyone who might want to take advantage.
Rollout progress was tracked closely. Node conversion went from 1.3% to 23.7% to 57.1% of the network in the days before the fork, with the TU release carrying most of the fleet over.
The upgrade notice sent to exchanges read:
Upgrade notice
SUMMARY: C29 proofs of work can be calculated faster than expected. Network difficulty has controlled overall chain growth. We’re releasing a fix that reduces the speed at which C29 proofs of work can be calculated.
IMPACT: This issue does not affect wallets or user funds. The fix requires a hard fork by block 350,000. Base nodes must be upgraded before the fork to remain on the supported chain and continue processing deposits and withdrawals.
REQUIRED ACTION: Upgrade all base nodes to v5.7.0-pre.10 before block 350,000.
Impact
There was no reorganization or contentious chain fork. All exchanges have been moved to the new chain. A single exchange had difficulty with the update, but the issue has been resolved as of writing, and the chain retains integrity. The multi-lane proof of work schema did its job and prevented a meaningful split.
The C29 lane was effectively hijacked for two weeks. Difficulty went from ~80,000 to peaks past six million — honest C29 miners were priced out of their own lane, and the attacker collected the lane’s block rewards and fees in the interim. Those rewards were on the accepted chain and remain there; the fork cut off the supply of new forged blocks, it did not retroactively unwind them.
Operational friction, not financial loss. Exchanges held deposits and withdrawals through the transition and re-enabled on the patched chain. The C29 lane’s share of blocks dropped from ~25–28% to 16.3% in the first ~500 post-fork blocks as the phantom hashrate vanished, and difficulty began falling immediately.
What Operators Should Do
Upgrade to v5.7.0-pre.10 or the follow-up release (v6.0.1-pre.0), which supersedes it. TU deployments auto-update.
If your node is already past block 350,000 on older software: upgrading to v6.0.1-pre.0 will automatically migrate and rewind if required. Upgrading via v5.7.0-pre.10 requires a manual rewind to 350,000 first — the release notes are explicit about this.
Pools and miners: upgrade your mining software. After the fork, proofs must be valid bipartite Cuckaroo cycles; pre-fork mining implementations produce merged-namespace proofs that will be rejected. The lane is safe once the majority of mining pools have upgraded.
Exchanges and services: confirm your node is on the patched chain before re-enabling deposits and withdrawals, and verify the tip against the fork block hash at the end of this report.
The Current State
Mainnet is past height 352,500 and ticking (352,590 as of September 25, 2026, ~19:00 UTC). All lanes are producing blocks; C29 difficulty has recovered and will adjust faster in the future due to the reduced LWMA window. The attacker’s cadence is gone entirely — within half an hour of the fork the C29 lane had found its first honest block, and the response was signed off as fixed.
The fix and its verification tooling are public in the repository, including the read-only scanner that re-verifies every historical C29 proof under both verifiers and reports any header the legacy verifier accepts but the bipartite verifier rejects.
The glass-half-full view: Tari took a consensus hit and came out with a hardened C29 lane, a faster-reacting difficulty algorithm, and a contact list that now survives the incident.
Acknowledgments
To momo, who found and reported the vulnerability. To SW and Brian, who worked tirelessly all through the weekend to get the fix rolled out and contact all pools and exchanges. To Impala, whose expansive infrastructure and validation were essential in testing and deploying the upgrade. To Naveen and Fox, who coordinated communication, messaging, and advised throughout. And to everyone at Kryptex, ST, LuckyPool, DXPool, Jagtech, the seed-node operators, and the exchanges who upgraded on a weekend because crypto doesn’t sleep.
Verify you’re on the right chain
The fork activation height: block 350,000 — block hash 663b7254df69989b33cec8325815631e2b455f7252c230976f1b50dc8daced47. Upgraded and non-upgraded nodes shared the chain until height 350,004, where the chains diverged. A block on the correct chain shortly after the divergence: height 350,004 — block hash 47001243d90dc735701fe3a0ce069731ec49d57a3bb4730259ec90d1745cde8c.
The first forged block, for reference: height 339,109 — block hash 7fbd9ad961f84f54af888578fab2cb7c9baa69e46e91ff0aa1b547e907b903db