TL;DR
On October 14, 2026, Pirate Chain found that someone had created about 39.8 million ARRR out of nothing, increasing supply by roughly 20%, and moved it straight into the Sapling shielded pool. Pirate's own fix commits name the hole. Block validation ran a branch for "mint" transactions that skipped input and burn-proof checks for coin imports as well as the coinbase, so an import-shaped transaction minted its outputs with no proof that anything was burned. A second flaw let a crafted script report a whitelisted address it did not actually pay, which could place funds in an output that passed the private chain's rule on transparent outputs. Pirate says the exploit combined the two. The project first announced a rollback, then said it could not unilaterally roll back, then shipped a mandatory 6.0.10 release and later checkpoints around a chain restart. No post-mortem is out yet. The 6.0.10 notes say imports are now verified in blocks "exactly as they are in the mempool," which we read as the relay path having checked them all along, so the forged coins most likely arrived inside a block.
What Happened to Pirate Chain?
Pirate Chain is a privacy coin where every transaction is shielded. At about 02:20 UTC on October 15, it posted on X that an exploit had been found "in the new transparent layer related to the Ironwood turnstile for supply accounting" and that developers would roll the chain back to 1:00 PM Pacific on October 14, which is 20:00 UTC. Exchanges were told to suspend deposits and withdrawals.
Fourteen hours later the follow-up statement gave the size. About 39.8 million ARRR had been created without authorization. The project said the exploit "combined two validation failures bypassing the issuance check and incorrect interpretation of the output scripts," that nothing pointed to compromised notary keys or broken zk-SNARK cryptography, and that NonKYC had spotted suspicious deposits and restricted the account behind them. It also reversed course on the rollback: "Because Pirate Chain is decentralized, it is not possible to freeze the network or unilaterally rollback its blockchain history." dPoW notary operators paused notarizations, and exchanges and mining pools were asked to pause voluntarily.
Ironwood is the reason the first post pointed where it did. Version 6.0.0 introduced Ironwood, a new shielded pool built on Halo2, with mainnet activation at 19:00 UTC on October 3. Crypto Briefing notes the flaw surfaced 11 days later. The fix commits point somewhere older than the new pool.
How Did a Coin Import Mint ARRR From Nothing?
Pirate Chain's node is built on Komodo code (its fixes touch files such as komodo_bitcoind.cpp and importcoin.cpp), and that code supports coin imports: a transaction that creates coins on one chain against proof that the same value was burned somewhere else. A coinbase creates coins too, but it pays the block reward and has no inputs to check. Both count as a "mint." In Pirate's transaction code, IsMint() returns true for either one, and an import is recognized purely by shape: one input whose prevout.n equals 1,000,000,000.
The fix commit, authored at 23:50 UTC on October 14, describes the bug in one paragraph. ConnectBlock, the function that applies a block to the chain, "skipped input and fee accounting for every IsMint() transaction." The burn proof lives in VerifyCoinImport, which runs inside ContextualCheckInputs. Imports took the mint branch, so they never reached it, "and its outputs were accepted with no proof of a burn." The repair changes one condition from tx.IsMint() to tx.IsCoinBase() and adds two tests that connect a block carrying a forged import and expect invalid-coin-import.
The commit also says imports are now "validated as before v6.0.0." That points at a regression, and the history confirms it. In an August 2025 commit titled "update consensus, disable gtest build", the ConnectBlock hunk deletes a block that used IsMint() only for supply accounting and rewrites the later input-check condition from if (tx.IsCoinBase()) to if (tx.IsMint()). After that merge, one IsMint() branch did two jobs in the pre-fix code: it added the transaction's outputs to the chain supply delta, and it skipped ContextualCheckInputs. The commit is an ancestor of the v6.0.0 tag.
Why Did the Output Script Bug Matter?
Pirate is a private chain. Transparent outputs are restricted by address, so the code decides whether an output is allowed by asking what address it pays. Freshly forged coins sitting in an ordinary transparent output would fail that rule.
The CLTV fix commit explains the second flaw. A CLTV (CheckLockTimeVerify) output is a time-locked payment: push a locktime, run OP_CHECKLOCKTIMEVERIFY, drop the value, then the normal payment script. ExtractDestination handles CLTV by skipping a fixed number of bytes and classifying whatever comes next. IsCheckLockTimeVerify, the test that decided a script was CLTV in the first place, used index arithmetic that only held for the canonical layout. A crafted script could pass as CLTV and have that byte offset land on "a payment template parked in dead pushed data," so the classifier reported an address the script did not require. In the commit's own words, "On this private chain that bypassed the transparent-output restriction." The code comment on the fix says the target was a whitelisted notary or CRYPTO777 address, and the 6.0.10 release notes add that such an output "passed the restriction while remaining spendable by the author."
Pirate says the exploit combined both failures, and the fix commits suggest how they fit: the import bug created the coins, and the script bug let them sit in an output the private-chain rule accepted while only the attacker could spend it. Pirate confirms the coins then went into Sapling, where nobody can follow them.
The Attack, Step by Step
This reconstruction combines Pirate's two statements with the fix commits and release notes. Pirate has not published the attacking block or transaction, so steps 1 to 3 and the flowchart below are our inference from the code and the release notes.
| Step | What happened | Source |
|---|---|---|
| 1 | Build an import-shaped transaction: one input with prevout.n of 1,000,000,000 and a payload that proves no burn | Fix commit da4e6252a |
| 2 | Give it an output script that parses as CLTV and reports a whitelisted notary/CRYPTO777 address, while staying spendable by the author | CLTV fix 3913cee40, 6.0.10 notes |
| 3 | Get the transaction into a block. The mempool path still verified imports, so this likely required a block the attacker mined or a miner included (our inference) | 6.0.10 notes |
| 4 | ConnectBlock sends it down the mint branch, skips ContextualCheckInputs, never runs VerifyCoinImport, and accepts the outputs | Fix commit da4e6252a |
| 5 | Spend the forged outputs into the Sapling shielded pool, about 39.8M ARRR in total | Pirate Chain update |
| 6 | Some of the funds reach NonKYC, which flags the deposits and blocks withdrawals | Pirate Chain update |
The 6.0.10 notes say imports "are now verified in block connection exactly as they are in the mempool." We read that as saying the mempool path had been checking them all along. If so, a forged import broadcast as a normal transaction would have been rejected by every node that saw it, and the only door left open was a block arriving with the transaction already inside.
Why Didn't the Turnstile Catch It?
A turnstile is a supply check for a shielded pool. Inside the pool nobody can see balances, so the chain tracks the public total that goes in and out, and ZIP 209 makes nodes reject any block that would drive a pool's balance negative. If a proof-system bug ever let someone forge notes inside the pool, more would come out than went in, and the turnstile would stop it.
Pirate added that rule in 6.0.0, in a commit that rejects blocks that would drive the cumulative Sapling or Orchard pool negative. The coins in this attack were forged on the transparent side and then deposited into Sapling. From the pool's point of view, that was a large, legitimate deposit, and its balance went up. A rule that fires on a pool going negative has nothing to say about that.
There was one number that did move. Pirate's node, like Zcash's, records a chain supply total and per-pool values in each block index and exposes them through getblock. In the pre-fix code, that same mint branch added a mint transaction's outputs to the supply delta, so the forged import was counted in the node's own supply figure the moment its block connected. As far as the public record shows, nobody was paging on it.
How Much Was Actually Lost?
The 39.8 million ARRR is Pirate Chain's own figure, and nobody can verify it on-chain, because the coins are shielded. At the $0.2614 CoinGecko price CoinGabbar recorded on October 16, that is about $10.4M on paper, against a market cap of $51.3M.
That dollar figure could never have been realized. CoinGabbar put 24-hour ARRR volume at $485,269 that day. Selling tens of millions of dollars of a coin that trades under half a million a day would take months and sink the price on the way, and the one venue Pirate named, NonKYC, froze the account. If the coins survive, a 20% supply increase leaves existing holders with about 83% of the new total. If they do not, the cost was a stalled chain and paused exchanges.
Which of those happened is the open question. Pirate said it could not roll back unilaterally. Five days later, a checkpoint commit pinned block 4,176,944 as the fork point, said the valid chain resumed at 4,176,945 on October 19, and rejects any block at those heights with a different hash. The same file marks block 4,161,185 as the Ironwood activation block, which per the 6.0.0 notes is the first block past 19:00 UTC on October 3, and dates block 4,168,315 to 19:19 UTC on October 8. Extrapolating that block rate puts the fork point close to 21:00 UTC on October 14, near the 20:00 UTC rollback the first post announced. That estimate is our arithmetic. Pirate has not said so. Whether the forged coins exist on the restarted chain is something only the promised post-mortem can settle.
What Was the Response Timeline?
| Time (UTC) | Event | Source |
|---|---|---|
| Aug 2025 | Commit rewrites the ConnectBlock input-check condition to IsMint(); it ships in v6.0.0 | Regression commit |
| Oct 3, 19:00 | Ironwood activates on mainnet | 6.0.0 release notes |
| Oct 14 | Vulnerability discovered; mint of about 39.8M ARRR | Pirate Chain update |
| Oct 14, 23:50 | Fix committed: proof of burn required for imports in ConnectBlock | Fix commit |
| Oct 15, ~02:20 | Pirate announces a rollback to 20:00 UTC Oct 14 | Crypto Times |
| Oct 15, 16:46 | Follow-up: 39.8M ARRR, two failures, no unilateral rollback | Pirate Chain update |
| Oct 18 | 6.0.10 released as mandatory, with an automatic reindex | 6.0.10 notes |
| Oct 19 | Valid chain resumes at block 4,176,945 | Checkpoint commit |
| Oct 20 | 6.0.12 locks the restarted chain with checkpoints | 6.0.12 notes |
The first public fix landed within hours of discovery. The chain still stalled for days while miners, pools, notaries and exchanges upgraded.
What Is the Precedent for This Bug?
The closest precedent is Bitcoin's. In 2018, Bitcoin Core disclosed CVE-2018-17144. An optimization had dropped a duplicate-input check from block validation, and a later redesign left only an assertion in its place. The result "could allow a miner to inflate the supply of Bitcoin." Same family: a check that ran in one path was quietly missing from block connection, and only someone producing a block could exploit it.
Shape predicates are security decisions. IsMint() means "creates coins." IsCoinBase() means "has no inputs to check." For years those were treated as interchangeable, because the only common mint was the coinbase. A coin import is a mint that does have something to check, and the moment one branch asked the broader question, the burn proof became optional. Any time a refactor swaps one classifier for a wider one, the review question is which transactions just gained a skip. Liquid Network's peg-out failed the same way, through a cache key that let a transaction skip its range proof.
Mempool and block paths drift apart. Nodes validate transactions twice, once on relay and once on connection, and the two paths are maintained separately. By the wording of Pirate's release notes, the mempool path here was correct, which would make the bug harder to see in testing, since a forged import submitted the normal way gets rejected. Same shape as the Ravencoin KAWPOW header bypass, where a shortcut path decided what got the full check.
The regression arrived in an August 2025 commit whose title says it also switched off the test build. Nothing public shows the two are connected, but they shipped together. The v6.0.0 tag that carried it into a release came a year later, two months before the mint.
Could an Audit or Monitoring Have Stopped It?
Monitoring could not have stopped the mint. A consensus bug means honest nodes accept the block, so no alert fires before it is on chain. What an alert changes is how long the forged coins move before anyone notices, and this incident offered signals worth alerting on:
- The supply figure jumped.
getblockreports a chain supply delta per block, and the pre-fix mint branch added the forged outputs to it. A delta of tens of millions of ARRR in one block, against ordinary block rewards, is not ambiguous. - An import-shaped transaction appeared in a block. One input with
prevout.nof 1,000,000,000 is a fixed, cheap pattern to match on every connected block. - The Sapling pool grew by about 39.8M ARRR. The per-pool values sit next to the supply figure in the same RPC.
Pirate has not said when on October 14 the mint landed or who spotted it first, so how much time alerts would have saved cannot be measured. NonKYC catching the deposits shows that an exchange watching for anomalies was the control that actually worked.
The prevention lane is review. The August 2025 diff carries the whole bug: a branch condition widened in ConnectBlock, beside a deletion of the block that used the same predicate. A reviewer tracing what each IsMint() caller skips finds it, and the CLTV classifier is the same exercise for script parsing. Our L1 chain audits cover consensus, the mempool and state-transition integrity, which is where a block check and a mempool check have to agree and where a widened branch like this one is found.
Operator Takeaways
- Alert on your node's own supply accounting. If your chain inherits Zcash-style
chainSupplyand value-pool fields, read them every block and page on any delta that exceeds the block subsidy. - Treat every widened classifier in validation code as a new skip path. When a diff replaces one predicate with a broader one (
IsCoinBasetoIsMint), list every branch that predicate controls and every check the new members now bypass. - Test the block path separately from the mempool. Write tests that connect a block containing an invalid transaction directly, because relay-path rejection will mask a block-path hole. Pirate's fix added exactly that test.
- Keep the test build on for every consensus change. The commit we trace this regression to also disabled the gtest build, per its title. Nothing public shows that the disabled tests hid this bug, but a consensus diff should never land without them. Gate merges to validation code on the full test build, and make "tests disabled" a release blocker rather than a footnote.
- Exchanges: run a validating node, upgrade fast, and hold deposits during supply anomalies. NonKYC's flag was the only containment Pirate reported. A deposit pipeline that checks chain supply before crediting can freeze an inflation exploit at the door.
Frequently Asked Questions
What was the Pirate Chain exploit?
On October 14, 2026, an attacker created about 39.8 million ARRR, a roughly 20% increase in supply, by getting a forged coin-import transaction into a block. Block validation skipped the burn-proof check for imports, and a script-parsing flaw let the output pass Pirate's restriction on transparent outputs. The coins went into the Sapling shielded pool.
Was Pirate Chain's zk-SNARK cryptography broken?
No. Pirate Chain said evidence does not indicate any compromise of notary keys or of the cryptography behind its shielded transactions. Both fixes sit in transparent-side validation: coin-import checks in ConnectBlock and CLTV script classification.
Did Pirate Chain roll back the blockchain?
Unconfirmed. The first post announced a rollback, and the follow-up said a unilateral rollback is impossible. The 6.0.12 release still added checkpoints around a restart at block 4,176,945, and our block-rate estimate puts the fork point near the announced rollback time. Whether the forged coins survive is unconfirmed pending the post-mortem.
How much was the stolen ARRR worth?
About $10.4M at the $0.2614 price CoinGabbar recorded on October 16, but that figure is notional. Daily ARRR volume was under $500K, the coins are shielded, and the one exchange Pirate named froze the account it found.
Would an audit have caught the Pirate Chain bug?
Yes, if the review covered the ConnectBlock change. The regression sits in a visible hunk of an August 2025 commit that widened a branch condition from IsCoinBase() to IsMint(), and the fix restored the narrower check.
Sources / References
- Pirate Chain on X: Import Exploit Update (Oct 15, 2026)
- Crypto Times: Pirate Chain Rolls Back Blockchain After Ironwood Turnstile Exploit
- Crypto Times: Pirate Chain Exploit Mints 39.8M ARRR, Rollback Plan Dropped
- Crypto Briefing: Pirate Chain exploit mints around 39.8 million ARRR, team proposes rollback
- CoinGabbar: Pirate Chain Exploit: Millions of New ARRR Created, Where Did They Go?
- PirateNetwork/pirate commit da4e6252a: Require proof of burn for coin imports in ConnectBlock
- PirateNetwork/pirate commit 3913cee40: Reject non-canonical CLTV scripts so output addresses can't be spoofed
- PirateNetwork/pirate commit a885c6d48: update consensus, disable gtest build (GitHub API)
- PirateNetwork/pirate commit 051003ebe: Clamp attacker-supplied values in coin-import and notarization parsing
- PirateNetwork/pirate commit af325ac2b: Checkpoint the valid chain across the 6.0.10 restart
- PirateNetwork/pirate commit 67ae8fae8: consensus: enforce ZIP 209 turnstile checks for Sapling/Orchard pools
- PirateNetwork/pirate commit 350efc029: Add chain supply and transparent value to block index
- PirateNetwork/pirate src/main.cpp at 53cfa711d1 (pre-fix ConnectBlock)
- Pirate Chain 6.0.0 release notes
- Pirate Chain 6.0.10 release notes
- Pirate Chain 6.0.12 release notes
- ZIP 209: Prohibit Out-of-Range Chain Value Pool Balances
- Bitcoin Core: Disclosure of CVE-2018-17144



