Migrating to v1.13.0¶
Every node on a v1.12.x release should move to v1.13.0, and track releases at ethereumclassic/core-geth. A resync is not part of the upgrade: your chain data carries over. Budget about twenty minutes of downtime.
Choose your guide¶
| You run the node on | Guide | Ways to update |
|---|---|---|
| Linux | Linux users guide | The release archive (x86-64, arm64 or 32-bit ARM), or a build from source |
| macOS | Mac users guide | The release archive (Apple Silicon or Intel), or a build from source |
| Windows | Windows users guide | The release archive, or a build from source |
| Docker | Docker users guide | The registry image, the release tarball, an image built from the release archive, or one built from source |
Every guide takes the same six steps: stop the node cleanly, install v1.13.0, rotate the P2P node key, re-check RPC exposure, start and verify, and roll back if you need to. The two steps every node shares are explained once, below.
What every node must do¶
Rotate the P2P node key¶
This step is required. CVE-2026-26315 is an oracle against the node key itself: an invalid-curve ephemeral key in the RLPx handshake previously reached ECDH and failed only at MAC verification, leaking key bits across repeated handshakes. A key used by an unpatched node should be treated as exposed.
With the node stopped, rename geth/nodekey in the data directory; your guide gives the command. Do not delete it: keeping it lets you prove which node an old enode ID belonged to. The client writes a fresh key on the next start.
Your enode ID changes. Update every place that names this node:
- A peer that names this node explicitly needs the new enode ID in its own configuration file, under
StaticNodesorTrustedNodesin[Node.P2P]. Editingstatic-nodes.jsonortrusted-nodes.jsonon that peer changes nothing: neither this release nor anyv1.12.xrelease reads those files. Support for them was removed upstream well before thev1.12.xseries, and a node that finds one logs an error instead of reading it:
1 | |
Put static and trusted peers in StaticNodes / TrustedNodes under [Node.P2P] in config.toml (Configuration; Troubleshooting). - peer configuration held by anyone who peers with you deliberately - monitoring, dashboards and allowlists that identify the node by enode
Your guide reads the new ID after the node comes up, in step 5.
Re-check RPC exposure¶
The node is down, which makes this the cheap moment to check it.
--http.addrshould be127.0.0.1unless a trusted proxy terminates in front of it.admin,debugandpersonaldo not belong in--http.apion any reachable interface.--http.corsdomain="*"allows any origin. Name the origins you actually need.- The same applies to
--ws.addrand--ws.api.
None of this is one of the six CVEs. It is the exposure that decides how much any future one costs you.
Why this migration¶
This upgrade is pressing, and it is advised for every node still on a v1.12.x release.
The CVEs. Six were reported against this client. The earliest v1.12.x releases carry all six unpatched; later ones close some and not others. v1.13.0 carries every fix, plus a GraphQL query depth limit. The March 2026 audit gives the per-release breakdown, if you need to know what your current version is exposed to.
The toolchain. Every v1.12.x archive measured was built on a Go version that is no longer supported, most recently Go 1.21 and Go 1.22, whose support ended in August 2024 and February 2025. A node built from one inherits whatever has accumulated in the Go runtime and standard library since, independent of anything in the client’s own code. v1.13.0 builds on Go 1.26.
Where releases come from. ethereumclassic/core-geth was created in December 2024 and is where release work continues. A node tracking the previous repository will not see v1.13.0.
What changes in v1.13.0¶
If you start the node without a network flag¶
v1.13.0 runs Ethereum Classic when no network flag is given, and --mainnet now means the same as --classic. If your command line already names --classic or --mordor, nothing in this section applies to you.
A v1.12.x node started without a flag was running Ethereum mainnet. If yours was, four things change:
- The data directory is Ethereum Classic’s. Without
--datadir, the node uses theclassicsubdirectory of the default location, the directory--classichas always used:~/.ethereum/classicon Linux,~/Library/Ethereum/classicon macOS and%LOCALAPPDATA%\Ethereum\classicon Windows. Data the old node kept ingethbeside it is left untouched and is not opened. - Accounts use the Ethereum Classic keystore. Without a flag, the node reads and writes keyfiles in
~/.ethereum/classic/keystore, the directory--classichas always used. - The cache is 1024 MB, as
--classichas always used. Pass--cacheto give the node more; it lowers any value above one third of the machine’s memory. - An explicit
--datadirkeeps the chain it holds. A private network initialized withgeth initkeeps running from its stored genesis, and a data directory holding Ethereum Classic is kept on the current Ethereum Classic configuration, as--classickeeps it. - A
--networkidother than 1 marks a private network. The node keeps the defaults it had in v1.12.x:~/.ethereumas the data directory, no Ethereum Classic bootnodes or discovery trees, and a 30000000 gas ceiling for mining. A private network started with neither a network flag nor--networkidgets Ethereum Classic’s defaults instead, so add--networkid, or pass--datadir,--bootnodesor--nodiscover, and--miner.gaslimit.
If your chain uses its own genesis or chainspec file¶
This affects private and custom networks only. Ethereum Classic, Mordor and the other networks built into the client are not affected.
v1.13.0 reads three kinds of value in a custom configuration differently from v1.12.x. The new reading matches go-ethereum’s.
| Value in the file | v1.12.x | v1.13.0 |
|---|---|---|
| A fork block number of 2^63 (9,223,372,036,854,775,808) or more | Active from genesis | Never reached |
| A negative fork block number | Its absolute value | 0 |
| A block number of 2^63 or more in the difficulty bomb delay schedule | Applied from genesis | Never applied |
If your file holds any of these, change it before you upgrade so that v1.13.0 applies the rule your chain actually ran with. Upgrading every node at the same time does not avoid this: the new reading also applies to past blocks, so a node syncing from genesis would replay them under different rules. For example, a fork set to 2^63 to mean “never” ran from genesis under v1.12.x; set it to 0 to keep that rule. A fork set to -5 ran from block 5; set it to 5.
MESS applies again, and you should decide about it¶
The release you are leaving activates MESS and then deactivates it at block 19,250,000, the Spiral block. v1.13.0 removes that deactivation, so an upgraded node applies it where your old one did not. Nothing about block validity changes: MESS decides which of two competing chains a node prefers when one arrives that would replace blocks it already accepted, which is what a majority-hashrate attack produces rather than ordinary mining. In normal operation a node with it on and a node with it off follow the same chain.
Decide before you finish the upgrade rather than after, and give every node in one fleet the same setting: deposit and withdrawal nodes that disagree can prefer different chains during a deep reorganization, which is worse than either setting.
- An exchange, a custodian, or a pool that credits deposits: leave it on. A deep reorganization is the attack aimed at you.
- A mining pool or solo miner: there is a cost either way, set out in Which setting fits which operator.
- To turn it off, start the node with
--mess=false.
MESS carries the record behind the default, and the confirmation calculator shows what it means for deposit confirmations.
What this migration does not require¶
- No resync. No finding in either audit corrupts chain data.
- No new account keys. These are network-layer and handshake issues; your keystore is not implicated. Rotate account keys only if
adminorpersonalRPC was reachable from an untrusted network. That is its own exposure, not one of these CVEs. - No genesis or chain-configuration change. ETC consensus rules are unchanged through Spiral, and v1.13.0 implements the same fork set as the release you are leaving.
- No datadir change. The instance directory stays
<datadir>/geth/and the IPC socket staysgeth.ipc. Both are set from constants in the client, not from the executable’s name. Renaming either is the one change that would force a resync, so do not.
What this client is for¶
Core-Geth is maintained for Ethereum Classic and Mordor. The other networks it advertises fall into two different categories, and the difference matters before you point a node at one.
MintMe.com Coin is carried forward deliberately. --mintme works in v1.13.0, and this release includes the MintMe hardfork enabling PUSH0 and MCOPY. It is scheduled for deprecation in a future release, and the reason it is here rather than already removed is to leave that community a modernized client to build from (one on a supported Go toolchain with the CVEs closed) instead of a fork of an abandoned one. Plan on that horizon, but v1.13.0 is a sound base to start from.
Ethereum and its testnets are not supported. Support stops at Cancun, and Ethereum has since moved two upgrades beyond it, Pectra and Fusaka, with Glamsterdam scheduled in the coming months. This client cannot follow Ethereum mainnet, Sepolia or Holesky, and is not intended to. --ethereum, --sepolia and --holesky are deprecated and refuse to start. With no network flag, or with --mainnet, the node runs Ethereum Classic.
On the wire this client speaks eth/68. eth/69 removes Total Difficulty from the handshake, which this client’s proof-of-work chain selection reads, so it is not adopted here.
Running a second client alongside this one is sound practice, because a network where most of the hashrate runs one implementation has a single point of failure whatever that implementation is. On one host, give the second node its own datadir and ports that do not collide with Core-Geth’s, which Ports and listeners lists. Two clients sharing a datadir will corrupt it.
Why this release exists¶
The environment those releases now sit in. The March 2026 attack went from a public disclosure to a working exploit against production bootnodes quickly, and the tooling for finding and weaponizing a disclosed flaw has continued to get cheaper and more automated since. An unmaintained client is not merely behind in that environment; it is a standing, published list of what to try. Closing the gap once is not sufficient: what a client needs is development that is continuously reviewed, continuously tested, and instrumented well enough that the next gap is visible while it is small. Rebuilding Core-Geth around that is as much a part of v1.13.0 as the patches are.
Three reports document the state of the v1.12.x line, all written before v1.13.0 was cut:
- March 2026 security audit: the six CVEs and the GraphQL denial of service, with the per-release breakdown.
- August 2026 security follow-up: v1.12.23, measured directly at the tag against the advisory records.
- Dependency and toolchain modernization: what changed underneath the code between the December 2024 archive and this release.
Read together they describe a line that went 21 months without a substantive release (v1.12.20 in June 2024, then nothing until March 2026) and was then patched under emergency conditions during a live attack, with changes merged without a second reviewer.
That last part is a security problem in its own right, separate from anything it fixed. A cryptographic patch that no one else reviews has no one positioned to catch a defect or a malicious change shipped under cover of an urgency nobody wants to slow down. v1.13.0 and the sunset period around it exist to close that condition, not only the vulnerabilities it produced.