October 30, 2026
Consensus exploit of 14 October 2026, chain restart, and what it means for holders
On 14 October 2026 a flaw in Pirate Chain’s consensus code was exploited to create approximately 39.8M ARRR out of nothing in block…

By KOSIUS
8 min read
On 14 October 2026 a flaw in Pirate Chain's consensus code was exploited to create approximately 39.8M ARRR out of nothing in block 4176945. The flaw was found the same day and fixed within 24 hours. The network has since abandoned the branch containing that block and restarted on a clean chain.
The short version:
- No wallet was drained. The attacker created new coins rather than taking anyone else's. No user funds were spent or stolen.
- The minted coins do not exist on the chain the network now follows. The branch containing the exploit was discarded, so the ARRR supply is intact and holders have not been diluted.
- Every node must run 6.0.10 or later. Older nodes still consider the bad block valid. The current release is 6.0.14.
- If transactions were confirmed between 14 and 19 October 2026, verify them. Anything confirmed on the abandoned branch after block 4176944 is not part of the current chain.
A note for operators of other chains: the second defect described below, in the script address-classification code, is inherited from the shared Komodo codebase, and anyone running a Komodo-derived chain should check their own tree against that fix. The first defect was a regression introduced by Pirate itself and is not present upstream.
What happened
A transaction was mined into block 4176945 that created roughly 39.8M ARRR without any backing. It was not a transaction that could be broadcast across the network; the mempool rejected it correctly, so it had to be mined directly into a block. The funds were placed in transparent outputs that the chain should have refused, then swept into Sapling and later moved into Ironwood.
Two separate defects in the consensus code had to line up. One let a specially shaped transaction skip the checks that confirm a transaction's inputs exist and cover its outputs. The other let a transparent output misreport which address it paid, slipping past the rule that restricts transparent outputs on Pirate to a small whitelist. Either defect on its own would have stopped the transaction. Both were in Pirate's own code, and one was a regression introduced by the project in August 2025 that shipped in v6.0.0.
The full mechanics are in the technical section below.
What it means for holders
Funds in wallets were never at risk from this. The exploit minted new coins; it did not give the attacker access to anyone else's keys, addresses or balances.
The supply is intact. Because a patched node treats block 4176945 as invalid, the network abandoned that entire branch. The minted ARRR is not in circulation on the chain being followed today. Anyone checking total supply against the figure from before 14 October 2026 should find it consistent.
The 14–19 October 2026 window needs attention. The valid chain stopped at block 4176944 on 14 October 2026 and resumed on 19 October 2026. Unpatched nodes continued building on the discarded branch during that period. If a transaction was sent or received in that window and confirmed on the old branch, it is not in the current chain. Balances should be checked, and anyone running a service (exchange, pool, payment processor) should reconcile deposits and withdrawals across those dates before resuming normal operation.
What to do
Upgrade to 6.0.14. On first start, a node upgrading from 6.0.9 or earlier performs a one-time reindex automatically so the corrected rules are applied to its stored chain. The reindex takes a while on a full node and should not be interrupted.
Nodes still on 6.0.9 or earlier will accept the invalid block and follow the wrong chain. They cannot be relied on for balances, and upgraded peers will reject them.
Technical detail
Relevant chain configuration
Two settings matter for understanding both defects.
-ac_private=1: Pirate is a shielded chain. A transparent output is only valid when its destination classifies as one of the notary addresses or CRYPTO777 (RXL3YXG2ceaB6C5hfJcN4fvmLH2C34knhA). Everything else must be shielded.
ASSETCHAINS_CC=0: CryptoConditions and cross-chain coin-import are disabled on Pirate, and Eval::ImportCoin always returns invalid. There is no legitimate coin-import on this chain and there never has been. That is what kept the first defect latent rather than obviously broken.
The transaction
It was a v4 with a single input whose prevout.n was 1,000,000,000, a two-byte scriptSig, and two outputs of 19,910,937.51865961 ARRR each. No burn proof, no real inputs, nothing backing it. It declared the outputs into existence and block validation accepted them.
That prevout index is the coin-import marker, and IsCoinImport() is nothing more than a shape check:
vin.size() == 1 && vin[0].prevout.n == 1000000000vin.size() == 1 && vin[0].prevout.n == 1000000000Any transaction with that shape counts as coin-import-shaped regardless of its contents. IsMint() is then simply IsCoinImport() || IsCoinBase(). That distinction is where the first defect lives.
First defect: mint-shaped transactions skipped input validation
In ConnectBlock, the branch deciding whether a transaction has its inputs validated was keyed on IsMint():
if (tx.IsMint()) {
// add the outputs to the supply, skip input validation
} else {
// ContextualCheckInputs (where VerifyCoinImport runs),
// plus the value-in >= value-out check
}if (tx.IsMint()) {
// add the outputs to the supply, skip input validation
} else {
// ContextualCheckInputs (where VerifyCoinImport runs),
// plus the value-in >= value-out check
}Only the coinbase is intended to take the first branch. Because IsMint() also covers coin-import, the transaction took that branch as well, which skipped ContextualCheckInputs, the only place VerifyCoinImport runs, along with the value conservation check. Its outputs were added to the supply.
The branch condition was changed from if (tx.IsCoinBase()) to if (tx.IsMint()) in commit a885c6d48 on 20 August 2025, with the commit message "update consensus". It shipped in v6.0.0 on 16 August 2026. The change originated in Pirate's own tree, so this defect is specific to Pirate and is not present in upstream Komodo or other chains derived from it.
Coin-import is disabled on Pirate through ASSETCHAINS_CC=0, and the rejection that applies is inside VerifyCoinImport. Because the branch skipped that call, the check that would have rejected the transaction was never reached.
Commit da4e6252a restores IsCoinBase(), so imports run VerifyCoinImport again and are rejected. It also adds tests covering rejection of import-shaped transactions at block connection.
Second defect: a transparent output could misreport its destination
Minting the coins was not sufficient on its own. The attacker needed somewhere to hold 39.8M ARRR that the chain would accept under the ac_private whitelist and that remained spendable by them.
That whitelist check classifies an output through ExtractDestination. For time-locked outputs it relies on CScript::IsCheckLockTimeVerify, then reads the payment template at a fixed offset of scriptPubKey[0] + 3, on the assumption that it is skipping the push opcode, the locktime bytes, OP_CHECKLOCKTIMEVERIFY and OP_DROP.
That arithmetic only holds for a canonical CLTV script, and the classifier was not verifying that the script was canonical. Two encodings got through: an OP_PUSHDATA1-encoded locktime (4c 01 b1 ...), which places 0xb1 exactly where the CLTV check looks, and a direct push not followed by OP_DROP. In either case the script was classified as CLTV, ExtractDestination then jumped scriptPubKey[0] + 3 bytes into a P2PKH template the attacker had placed in dead pushed data, and reported CRYPTO777.
So the output appeared to pay CRYPTO777 and passed the whitelist, while in fact being a hashlock only the attacker could open. From there the funds were shielded.
Commit 3913cee40 makes IsCheckLockTimeVerify require the exact canonical layout: a direct push of a one to five byte locktime with op == size, followed by OP_CHECKLOCKTIMEVERIFY and then OP_DROP. The first attempt at this fix was incomplete. It closed the OP_PUSHDATA1 encoding and missed the direct-push case; a follow-up audit caught that, and the OP_DROP requirement was added. Pirate does not create CLTV outputs at all, since timelock is off, so no legitimate output is affected.
This defect does not create value. It only affects how an output's destination is classified, and the value conservation checks sit in a separate path that it never touches. Its consequence on Pirate is that a transparent output can misreport which address it pays, which defeats the ac_private whitelist and allows shielded funds to exit to an attacker-controlled transparent output. That is a policy bypass rather than inflation. It mattered here because it gave the minted coins somewhere the chain would accept them while remaining spendable by the attacker; minting directly to a whitelisted address would have produced coins only the whitelist key holder could spend.
Unlike the first defect, this classification code is inherited from the shared Komodo codebase rather than written for Pirate, so other Komodo-derived chains are likely to carry it and should apply the equivalent fix. Exposure depends on configuration: a chain that gates transparent outputs by classified address, as Pirate does, can have that gate bypassed, while a chain that permits transparent outputs generally has materially less at stake, since there is no gate to bypass.
Why the mempool did not stop it
The mempool path does run VerifyCoinImport, so the transaction was rejected on relay and could not propagate. The gap existed only in ConnectBlock.
That means the transaction could not be broadcast. It had to be mined directly, which narrows considerably the set of people able to carry it out, but it still happened. The more important point is that a consensus rule behaved differently depending on whether a transaction arrived in a block or over the wire. That divergence should not have been possible.
What else contributed
Nothing tested for it. A consensus-critical change from IsCoinBase() to IsMint() went in without any test asserting that an import-shaped transaction is rejected at block connection on a chain where imports are disabled. Had that test existed in August 2025, none of this would have happened.
There is also no transparent supply check. The ZIP-209 turnstile guards only the shielded pools, rejecting a block if cumulative Sapling or Ironwood value goes negative. The running transparent pool value and the total supply are computed on every block and then never examined. A defect that inflates the transparent supply therefore has nothing watching it at the chain level, and the shielded turnstile is entirely blind to what happened here. That is the one invariant whose absence maps directly onto this exploit, and the most significant gap remaining.
Two parsers were also less defensive than they should have been. GetCoinImportValue did not clamp the attacker-supplied burn value to MoneyRange, and komodo_verifynotarization decoded a hex string from a remote daemon into a fixed _script[8192] buffer without bounding the length. Neither was reachable to cause the mint on Pirate, but both were hardened in 051003ebe rather than left in place.
The fixes and how they were verified
Three commits, all in 6.0.10, which was cut as a mandatory release:
da4e6252a(14 October 2026) restoresIsCoinBase()inConnectBlock.3913cee40(15 October 2026) requires canonical CLTV inIsCheckLockTimeVerify.051003ebe(15 October 2026) hardens the two parsers above.
MIN_INDEX_VERSION was also raised to 6001000 so any node upgrading from 6.0.9 or earlier performs a one-time reindex, and startup logging was added for the stored block-index version and whether checkpoints are enabled, so an operator can confirm what state a node is actually in.
Checkpoints couldn't have fixed this. The checks that reject the block don't depend on them. VerifyCoinImport runs inside ContextualCheckInputs, the ac_private classification rule runs during transaction checks, and the value-in against value-out comparison runs in CheckTxInputs. None of those are skipped when checkpoints are enabled or when fExpensiveChecks is off, so a patched node rejects 4176945 either way.
That is the right behaviour, but it ruled out the simpler recovery. No checkpoint could be placed that would let the chain carry on past that block, so the branch had to be abandoned.
Verification came from two independent full reindexes with -checkpoints=0, which validates every block from genesis with nothing skipped. Both rejected 4176945 and accepted every preceding block, identically across runs. That is the required result: the fixes bite on the bad block and do not false-reject any legitimate history.
A series of audits also covered the acceptance path, including transaction and block validity, the Komodo special cases, the script classifier and executor, the ac_private gating, the CC, import and OP_RETURN parsers, value conservation arithmetic, reorg and undo rollback, mempool versus block parity, and the Ironwood activation boundary. Nothing else exploitable was found.
Restoring the chain
Because a patched node treats 4176945 as a consensus failure, recovery was a network problem rather than a code one. Patched nodes reindex, reject the block and hold at 4176944. The valid chain resumed with a new 4176945 on 19 October 2026.
The resumed chain has since been pinned with hardcoded checkpoints at 4176943 and 4176944, the last two blocks before the stall, the valid 4176945, and 4177100 further on, so that no node can follow the discarded branch.
Timeline
- 20 August 2025 —
a885c6d48replacesIsCoinBase()withIsMint(). - 16 August 2026 — ships in v6.0.0.
- 14 October 2026 — exploit mined in block 4176945, identified the same day, coin-import fix committed.
- 15 October 2026 — CLTV fix and parser hardening committed.
- 14–18 October 2026 — audits and the two
-checkpoints=0reindex runs. - 19 October 2026–6.0.10 rolled out, exploit branch abandoned, chain restarted.
- Since 19 October 2026–6.0.11, 6.0.12 and 6.0.14 released with networking and connectivity fixes, plus the restart checkpoints.