Summary
Upgrade to Core-Geth v1.13.0 or Later, and Rotate Your Node Key
Core-Geth went 21 months without security maintenance, from v1.12.20 in June 2024 to the emergency releases of March 2026. Six CVEs and a GraphQL denial of service accumulated in that window. Two of them, CVE-2026-22862 and CVE-2026-26315, were exploited against the Ethereum Classic mainnet bootnodes on 18 March 2026, where one bootnode crash-looped through more than 805 restarts before a patch reached it.
7
findings, unpatched through the gap
21 months
with no security maintenance
98%
of Core-Geth nodes not yet on v1.13.0
55 to 61
Go advisories in each v1.12.x archive
The three releases cut in response did not close the line. Every v1.12.x build, v1.12.23 included, still carries at least one unpatched CVE and still serves the GraphQL endpoint with no query depth limit, and every published archive was built on a Go release that had already left support. The v1.12.21 archives also raised the Linux glibc floor, so an operator on Ubuntu 20.04, Debian 11, RHEL 8 or Amazon Linux 2 could not run the security release they were told to install.
Core-Geth v1.13.0, released from ethereumclassic/core-geth on 14 September 2026, fixes every finding and is built with Go 1.26.8, with no Go standard library advisory reported against its archives. Run the current release; a node tracking the previous repository will not see it. Rotate the P2P node key as you upgrade rather than merely considering it: CVE-2026-26315 is an oracle against that key, so a key used by an unpatched node should be treated as exposed. Rename the key file rather than deleting it, and expect the enode ID to change.
Background
How This Was Found
During cross-client testing, the Ethereum Classic core developers found that etclabscore/core-geth, then the primary Ethereum Classic execution client, had received no security maintenance since its v1.12.20 release in June 2024. Six CVEs and a GraphQL depth-limit denial of service had accumulated unpatched, and every binary was built on Go 1.21 or Go 1.22, whose support ended in August 2024 and February 2025.
Private disclosures sent to that repository in 2025 received no response. Neither did the community pull requests that named the vulnerabilities in public, one of which linked the advisory for CVE-2025-24883 in June 2025, nor the public disclosure by a Ledger security researcher in February 2026. An attack on ETC bootnodes in March 2026 was what produced the emergency v1.12.21 and v1.12.22 releases, which backported some of the CVE fixes onto the same end-of-life toolchain and left the rest open. The ETC Cooperative, which controls that repository, had entered maintenance mode at the end of 2024 and published that maintenance of the client would fall to other stakeholders.
The full remediation began in February 2026 and was published at ethereumclassic/core-geth, the community repository created in December 2024. Those pull requests, filed in the repository the client had moved to, stayed open for five and a half months.
The previous repository went on publishing over the same period. Its first maintainer response to the February disclosure is dated 18 March 2026, the day the attack began, and three further releases followed: v1.12.21 merged 70 minutes after it opened, v1.12.22 in under two minutes, and v1.12.23 in August, none of them carrying a recorded review.
The community repository's work reached operators as Core-Geth v1.13.0 on 14 September 2026, from code that had been public since February.
March 2026
The March 2026 Attack on Core-Geth v1.12.x Nodes
On 18 March 2026, the ECIES handshake path was actively exploited against the ETC mainnet classic bootnodes ams3 and sfo3. Two defects in that path were reachable by any unauthenticated peer: CVE-2026-22862, the decrypt length undercheck (CVSS 7.5 High, GHSA-mr7q-c9w9-wh4h), and CVE-2026-26315, the invalid-curve key oracle in GenerateShared (CVSS 5.9 Medium, GHSA-m6j8-rg6r-7mv8). Malicious P2P traffic sent crafted auth messages with undersized ECIES payloads, crashing each node on inbound handshake attempts. Because the crash occurred in listenLoop, the node process exited and restarted under the service manager — only to crash again on the next malicious connection, producing an automated crash-loop. Bootnode sfo3 accumulated 805+ restart cycles on v1.12.20 before the patch was deployed.
panic: runtime error: makeslice: len out of range
goroutine 42797 [running]:
github.com/ethereum/go-ethereum/crypto/ecies.symDecrypt(...)
crypto/ecies/ecies.go:224
github.com/ethereum/go-ethereum/crypto/ecies.(*PrivateKey).Decrypt(...)
crypto/ecies/ecies.go:322
github.com/ethereum/go-ethereum/p2p/rlpx.(*handshakeState).readMsg(...)
p2p/rlpx/rlpx.go:612
github.com/ethereum/go-ethereum/p2p/rlpx.(*handshakeState).runRecipient(...)
p2p/rlpx/rlpx.go:415
github.com/ethereum/go-ethereum/p2p/rlpx.(*Conn).Handshake(...)
p2p/rlpx/rlpx.go:308
github.com/ethereum/go-ethereum/p2p.(*Server).listenLoop.func2()
p2p/server.go:921Stack trace from issue #692. PR #694 (v1.12.21), which cherry-picked the fix for both defects, was opened and merged by its author 70 minutes later, with no review, and the release followed about five hours after the crash was first reported: the first code activity from the upstream maintainer in 14 months.
Timeline
Release Timeline
Core-Geth v1.12.20 released at etclabscore/core-geth
Last release before a 21-month gap in security maintenance
Go 1.21 reaches end-of-life
Build toolchain unsupported, runtime CVEs accumulate unpatched
Last upstream commit before the 2026 emergency releases: a GitHub Actions CI update
No code changes recorded in the period that follows
Security disclosures sent to upstream maintainer
No response recorded
Ledger security researcher publicly discloses three CVEs in issue #692
No maintainer response until March 18
All six CVEs patched by White B0x
CVE-2025-24883, CVE-2026-22862, CVE-2026-26315, CVE-2026-26314, CVE-2026-22868, CVE-2026-26313
Go toolchain upgraded 1.21 → 1.26
Commit b7d164018; blst v0.3.11 → v0.3.16
v1.12.21 ("Aegis") released at etclabscore/core-geth during the bootnode attack
Emergency ECIES patch. Two of six CVEs backported and four left open, the GraphQL depth limit untouched, the Go 1.21 toolchain unchanged, and the Linux glibc floor raised from 2.17 to 2.34
Fixes submitted to ethereumclassic/core-geth as pull requests #10 to #36
The CVEs one per pull request in #10 to #20, each with a linked advisory, then the test and documentation work behind them
v1.12.22 ("Hermes") released at etclabscore/core-geth
Remaining CVE backports, but CVE-2026-26313 only mitigated with a CPU amplification path open and CVE-2026-22868 left unfixed; eth_syncing regression introduced; Go 1.21 toolchain unchanged
v1.12.23 ("Argos") released at etclabscore/core-geth
p2p hardening only. CVE-2026-22868 and the eth_syncing regression still unfixed, a storage-range response cap can disconnect peers that answer correctly, still built on Go 1.21, and the glibc floor still 2.34
Core-Geth v1.13.0 released at ethereumclassic/core-geth
Six CVEs and the GraphQL depth limit fixed; built with Go 1.26.8
What Operators Need to Do
Status by Release
The findings apply to every release in the v1.12.x line, including the most recent. If you run any of them, upgrade to Core-Geth v1.13.0 or later and rotate your node key, as the migration guide describes.
June 10, 2024 and before
30.2% — 158 nodes, across v1.12.17 to v1.12.20
All six CVEs and the GraphQL denial of service unpatched. Built on Go 1.21 and, for its Windows and Arm archives, Go 1.22, which reached end of life two and eight months later.
March 18, 2026
9.5% — 50 nodes
Cut during the live attack on ETC bootnodes, about five hours after the crash was reported. Backports CVE-2026-22862 and CVE-2026-26315, leaving CVE-2025-24883, CVE-2026-26313, CVE-2026-26314 and CVE-2026-22868 open and the GraphQL depth limit unaddressed. Still built on Go 1.21 and Go 1.22.
March 28, 2026
31.5% — 165 nodes
Backports CVE-2025-24883 and CVE-2026-26314 and mitigates CVE-2026-26313 with a CPU amplification path left open. CVE-2026-22868 is left unfixed and the GraphQL depth limit unaddressed. Introduces an eth_syncing regression that reports highestBlock incorrectly (#697). Still built on Go 1.21 and Go 1.22.
August 14, 2026
26.3% — 138 nodes
A p2p hardening series that hardens CVE-2026-26313 further. CVE-2026-22868 is still unfixed, the GraphQL depth limit is still unaddressed, the eth_syncing regression is not fixed, a storage-range response cap can disconnect peers that answer correctly, and the archives are still built on Go 1.21 and Go 1.22.
September 14, 2026
1.7% — 9 nodes
Every finding in the audit and its follow-up fixed. Built with Go 1.26.8 and released from ethereumclassic/core-geth.
The v1.12.22 release notes attach CVE-2026-26315, which v1.12.21 had already fixed, to the fix for CVE-2026-26314, so matching those notes against the advisory records shows CVE-2026-26314 as unaddressed when it shipped in v1.12.22. The v1.12.21 and v1.12.23 release notes carry no advisory identifiers.
The August 2026 follow-up measures v1.12.23 at its tag and reconciles every identifier
Shares are of the 524 Core-Geth nodes seen on etcnodes.org on 17 September 2026, of 550 nodes in total. A further four report v1.12.24, which is a development build of the previous repository's master branch rather than a release. These figures move, and etcnodes.org carries the current breakdown.
CVE Analysis
CVE Gap Analysis
The following vulnerabilities were present in etclabscore/core-geth at v1.12.20. All are fixed in Core-Geth v1.13.0.
Missing IsOnCurve check in UnmarshalPubkey — off-curve secp256k1 points pass deserialization without error, causing invalid results in any downstream ECDSA or ECDH operation.
Component: crypto/crypto.go — UnmarshalPubkey()
Affected: etclabscore/core-geth ≤ v1.12.20
In v1.12.x: Backported in v1.12.22
Fixed in: ethereumclassic/core-geth v1.13.0
CVSS 3.1: 7.4 High
Fix: 681c915f0
ECIES Decrypt() length check used +1 instead of +params.BlockSize (16). Crafted RLPx auth messages with undersized ECIES payloads cause an out-of-bounds read — remote crash during P2P handshake, no authentication required.
Component: crypto/ecies/ecies.go — Decrypt()
Affected: etclabscore/core-geth ≤ v1.12.20
In v1.12.x: Backported in v1.12.21
Fixed in: ethereumclassic/core-geth v1.13.0
CVSS 3.1: 7.5 High
Fix: c46834dd8
ECIES GenerateShared() accepted unvalidated ephemeral public keys into ECDH. A MAC-oracle attack using repeated unauthenticated RLPx handshakes can leak bits of the node's static P2P private key.
Component: crypto/ecies/ecies.go — GenerateShared()
Affected: etclabscore/core-geth ≤ v1.12.20
In v1.12.x: Backported in v1.12.21
Fixed in: ethereumclassic/core-geth v1.13.0
CVSS 3.1: 5.9 Medium
Fix: c19892395
IsOnCurve() did not verify coordinates are strictly less than the curve prime P. Out-of-field coordinates satisfy the naive curve equation via modular arithmetic and bypass the validity gate, leading to undefined scalar multiplication results.
Component: crypto/secp256k1/curve.go — IsOnCurve(); C ext secp256k1_ext_scalar_mul()
Affected: etclabscore/core-geth ≤ v1.12.20
In v1.12.x: Backported in v1.12.22, whose release notes label it CVE-2026-26315
Fixed in: ethereumclassic/core-geth v1.13.0
CVSS 3.1: 8.1 High
Fix: c19892395
P2P message handler validated payload size (10 MiB cap) but not the number of RLP list items. A crafted header declaring millions of tiny items allocates per-item memory before validation — remote OOM crash via a single P2P message from any connected peer. v1.13.0 holds each message as an undecoded rlp.RawList until it is validated, and matches every response to a pending request.
Component: eth/protocols/eth/, eth/protocols/snap/, p2p/tracker/
Affected: etclabscore/core-geth ≤ v1.12.20
In v1.12.x: Mitigated in v1.12.22 with a CPU amplification path left open, then hardened further in v1.12.23
Fixed in: ethereumclassic/core-geth v1.13.0
CVSS 3.1: 7.5 High
Fix: 7a4988919
CVE-2026-22868MEDIUMFIXED IN v1.13.0KZG blob proof validation DoS — invalid proofs trigger full expensive cryptographic verification without disconnecting the offending peer. Ethereum Classic has no blob transactions, so the path is not reached in normal operation; v1.13.0 fixes it regardless.
Component: core/txpool/validation.go — validateBlobSidecar(); eth/fetcher/tx_fetcher.go — Enqueue()
Affected: etclabscore/core-geth ≤ v1.12.20
In v1.12.x: Declared not applicable to ETC and left unfixed
Fixed in: ethereumclassic/core-geth v1.13.0
CVSS 3.1: 5.3 Medium
Fix: 9985c33fb
GraphQL Depth DoSMEDIUMFIXED IN v1.13.0No query depth or complexity limit on the GraphQL endpoint (--graphql flag). Deeply nested queries exhaust CPU and memory. v1.13.0 limits query depth to 20. GHSA-mh3m-8c74-74xh, a stack overflow reachable only once a depth limit is enabled, is already fixed in the graphql-go v1.3.0 the client used, and v1.13.0 ships graphql-go v1.10.2.
Component: graphql/service.go
Affected: etclabscore/core-geth ≤ v1.12.20
In v1.12.x: Not addressed in any release
Fixed in: ethereumclassic/core-geth v1.13.0
CVSS 3.1: 7.5 High, where the endpoint is exposed
Fix: 6a046ee910
The March 2026 audit carries the per-CVE analysis and the disclosure timeline
Go Toolchain
Go Runtime End-of-Life
Each v1.12.x release was built by two toolchains, not one. The Linux and macOS archives, and the Windows archives from v1.12.21, were built with Go 1.21; every Arm archive, and v1.12.20's Windows archive, was built with Go 1.22. Go's release policy provides security patches only for the two most recent major versions, so support ended in August 2024 for Go 1.21 and February 2025 for Go 1.22. As of the March 2026 audit, Go 1.21 had been unsupported for 19 months, leaving the standard library (net/http, crypto/tls, crypto/x509) unpatched across that window. Core-Geth measured each published archive: every v1.12.20 to v1.12.23 archive carries 55 to 61 Go standard library advisories that v1.13.0 does not.
Core-Geth v1.13.0 at ethereumclassic/core-geth is built with Go 1.26.8, and a scan of its archives reports no Go standard library advisory at all. The v1.12.x source cannot simply be rebuilt on a supported Go: its release build stops in blst v0.3.11 from Go 1.24, and at the linker in fjl/memsize from Go 1.23. v1.13.0 carries blst v0.3.17, no memsize, and go 1.26.0 in its module file. Commit: b7d164018. The Go toolchain audit lists every advisory and how each archive was measured.
Artifacts
What the Published Archives Contain
A release is what the archive contains, not what the build configuration says it builds, and the two can disagree for a long time without anything reporting it. The build succeeds, the tests pass, the archive is well formed and the checksum matches. Core-Geth measured the published archives by opening them.
The Linux platform floor moved without being announced. v1.12.20 required GLIBC_2.17; v1.12.21 raised it to GLIBC_2.34and v1.12.22 and v1.12.23 held it there. glibc 2.34 merged libpthread and libdl into libc, so a binary linked against it acquires that whole symbol family at that version, and no change in the source causes it. Ubuntu 20.04, Debian 11, RHEL and Rocky 8, and Amazon Linux 2 all ship older glibc. An operator on any of them could run v1.12.20 and could not run the security release they were told to upgrade to. Every Arm archive moved the same way in the same release.
The macOS archive changed architecture under a fixed name. core-geth-osx-<version>.zip carried an x86_64 binary at v1.12.19 and an Apple Silicon binary from v1.12.20 onward, under a name that records no architecture. An Intel Mac user following the same download path as always receives a binary their machine cannot execute, and the failure appears when they run it rather than when they download it.
v1.13.0 states the platform floor as a build input and fails the release when an artifact does not meet it, restoring GLIBC_2.17 on x86_64 and each Arm target to the floor v1.12.20 shipped. It publishes both macOS architectures under names that say which is which, and every archive and image carries a checksum and a build attestation.
The release-artifact audit lists every measurement and how each archive was read
Risk Assessment
Risk Assessment
Remote crash via RLP (CVE-2026-26313)
Any peer on the ETC network can crash a node with a single crafted P2P message — no authentication, no prior relationship required.
Mitigation: Fixed in v1.13.0: responses are decoded lazily and bounded by the request they answer. Commit 7a4988919.
P2P key oracle (CVE-2026-26315 + CVE-2026-26314)
Repeated unauthenticated RLPx handshakes with crafted ephemeral keys can leak bits of the node's static private key across the 21-month exposure window.
Mitigation: Fixed in v1.13.0 by commit c19892395, which validates public keys before ECDH and closes both identifiers. Rotating the P2P node key after upgrading is required: rename the key file rather than deleting it, and expect the enode ID to change.
Remote crash via ECIES (CVE-2026-22862)
Off-by-fifteen length check in ECIES Decrypt() allows undersized ciphertext to trigger an out-of-bounds read during the RLPx handshake.
Mitigation: Fixed in v1.13.0 by commit c46834dd8, which measures the ciphertext against the AES block size rather than a single byte.
Go Runtime End-of-Life
Every v1.12.x archive was built on a Go version that is no longer supported: Go 1.21 for the Linux, macOS and later Windows archives, and Go 1.22 for every Arm archive and v1.12.20's Windows archive. Support ended in August 2024 and February 2025, and by the March 2026 audit the standard library had gone 19 months without patches.
Mitigation: Core-Geth v1.13.0 is built with Go 1.26.8, by commit b7d164018, which also carries blst forward so the line builds on a current compiler.
Single unmaintained upstream
No response to security disclosures sent during 2025. The etclabscore/core-geth repository received no substantive code commit between June 2024 and the March 2026 emergency releases.
Mitigation: Maintenance moved to ethereumclassic/core-geth, which has more than one maintainer with admin access and takes pull requests. Releases are published there, and a node tracking the previous repository will not see them.
21-month release gap
The 21-month gap between v1.12.20 (June 2024) and the March 2026 emergency releases is the longest maintenance gap in ETC network history.
Mitigation: Funding routes are published at docs.coregeth.com/support/, behind the repository's Sponsor button. ECIP-1112, the Sovereignty Vault, is a draft that would accumulate base-fee revenue for this work, and that revenue is raised from the network's own usage.
CPU amplification in v1.12.22 (CVE-2026-26313)
v1.12.22 stops the out-of-memory crash but scans the whole RLP payload before rejecting an oversized message: about 2,500 times the work per attack message that v1.13.0 does, so a peer can still exhaust CPU.
Mitigation: Fixed in v1.13.0, which bounds each response by the request it answers. Commit 7a4988919.
Unreviewed emergency releases
The v1.12.21 and v1.12.22 pull requests were each opened and merged by the same account with no review recorded on GitHub: the first about 70 minutes after opening, the second in 95 seconds. Neither v1.12.23 pull request records a review either. With no second reviewer, a defective or malicious change shipped under cover of an emergency has nothing to catch it.
Mitigation: From v1.13.1 a change reaches main only with an approving review from someone other than its author, with continuous integration required alongside that review rather than in place of it. Commit a6cc29b9d names the core developers team as code owners, so an author always has a reviewer. v1.13.0 predates the rule and carries no second-reviewer approval either.
Single-operator dependency
The client, the public RPC endpoint the ecosystem pointed at, and the peer discovery lists compiled into releases were each run by one organization, whose board has communicated that it is winding down. The endpoint went offline in late August 2026 without notice, and anything holding it in configuration stopped working.
Mitigation: Commit eb0cb35a9 compiles into v1.13.0 the discovery trees and bootnodes the community organization publishes on domains it holds, so no release ships a list that can go dark with one operator. --bootnodes and --discovery.dns accept any other list, and from v1.13.1 no single account can put one into a release unreviewed (a6cc29b9d).
Evidence Trail
Postmortem: Public Evidence Trail
The following issues, pull requests and releases at etclabscore/core-geth and the community repository form a linkable evidence trail. Each entry before the attack was a missed opportunity to prevent it; the last two record how the v1.12.x line ended and where the findings were resolved.
geth version-check to surface CVE advisories
Filed by one of the core maintainers five years before the attack: add CVE tracking to version-check. Had it been implemented, the 2025–2026 advisories would have surfaced in every node operator's log.
Merge go-ethereum v1.14
Community maintainer prepared a full v1.14 merge, noted it was "ready for merge." Remained open through the March 2026 emergency.
Dependabot: bump golang.org/x/crypto 0.17→0.31
Automated tooling upgraded the exact dependency affected by CVE-2026-22862 — later exploited in production. Auto-closed when a newer version superseded it. No human reviewed it.
Support go 1.24 — includes CVE-2025-24883 fix
Community member @tornadocontrib explicitly referenced CVE-2025-24883 with a link to the advisory. Available for 9 months before the attack. Closed when contributor deleted their fork. No review, no response.
Automated: remove unresponsive bootnodes
Bootnode health check flagged deployed ETC bootnodes as unresponsive — some already experiencing intermittent crash-loops from early exploit probing.
Security vulnerabilities in go-ethereum affecting core-geth
Ledger security researcher publicly disclosed CVE-2025-24883, CVE-2026-22862, and CVE-2026-22868 on 4 February 2026. First maintainer response: 18 March 2026 — the day the attack began.
Olympia upgrade cross-client sprint — all CVEs patched and Go toolchain modernized
Preparing Core-Geth as a reference client for the Olympia multi-client upgrade required a full modernization sprint. Starting February 26, 2026, White B0x authored CVE-2025-24883, then the Go 1.21 → 1.24 toolchain upgrade that removed the fjl/memsize lock-in, the remaining five CVEs, and the Go 1.24 → 1.26 final upgrade, all on the white-b0x/core-geth main branch and all in public while the previous repository had shipped nothing.
Release v1.12.21 ("Aegis") — emergency ECIES patch
Published during the active attack on bootnodes ams3 and sfo3, and the first code activity from @diega in 14 months. Two of the six CVEs were backported. CVE-2025-24883 stayed open, nine months after a community pull request linked its advisory and a month after White B0x fixed it in public; CVE-2026-26313, CVE-2026-26314 and CVE-2026-22868 stayed open with it, the GraphQL depth limit was untouched, and the toolchain stayed on Go 1.21 and Go 1.22.
The sprint opened as scoped pull requests at ethereumclassic/core-geth
The sprint was refactored into individually scoped pull requests and opened against ethereumclassic/core-geth on 20 and 21 March: one per CVE in #10 to #20, each with a linked advisory, then the test, documentation and rlp backport work behind them. They were filed against the old master branch and stayed open until 4 September, when each was closed as included in main. This is the version of the patches that appeared in v1.12.22 a week later, which its release notes do not reference, and it shipped as Core-Geth v1.13.0 on September 14, 2026.
Release v1.12.22 ("Hermes") — remaining CVE backports
Merged in under 2 minutes with no pre-merge review, carrying the White B0x work that had been public since 20–21 March, which its release notes do not reference. It carried the remaining backports but left CVE-2026-26313 mitigated with a CPU amplification path still open and CVE-2026-22868 unfixed, introduced the eth_syncing regression reported in #697, and left the toolchain on Go 1.21 and Go 1.22.
Incorrect RPC eth_syncing response with v1.12.22
Regression introduced by v1.12.22: highestBlock reported incorrectly. Services relying on eth_syncing for sync status receive wrong data.
Release v1.12.23 ("Argos") — p2p hardening series
Opened and merged by the same account 169 minutes apart, with no review or comment recorded. CVE-2026-22868 is still unpatched, declared not applicable because Ethereum Classic has no blob transactions, though the binary still ships the Ethereum code paths and flags that carry it and its Ethereum support reaches only Cancun. The eth_syncing regression stayed unfixed, a storage-range response cap could disconnect peers that answered correctly, the archives were still built on Go 1.21 and Go 1.22, and measured from the files themselves they require glibc 2.34 against v1.12.20's 2.17, so an operator on Ubuntu 20.04, Debian 11, RHEL 8 or Amazon Linux 2 could not run the release they were told to install.
Core-Geth v1.13.0 released at ethereumclassic/core-geth
The security pull requests opened at the community repository on 20 March 2026 targeted the old master branch. They were closed on 4 September as included in main, each closing comment naming the commit that carried it, and the release followed ten days later: six CVEs and the GraphQL depth limit resolved, on Go 1.26.8.
Root Cause
Structural Failures
Five independent structural failures — any one of which, if addressed, would have been sufficient to prevent the March 2026 attack.
No CVE Tracking Infrastructure
Issue #292 (2021) requested built-in CVE tracking in version-check. Never implemented. Operators had no automated signal that their client was exposed — they had to independently monitor the go-ethereum advisory database.
Automated Security PRs Unreviewed
Dependabot filed security bump PRs for golang.org/x/crypto and golang.org/x/net across January–April 2025, all unreviewed or auto-closed. PR #683 cited CVE-2025-24883 by name and stayed open for 9 months, closing when its author deleted their fork.
Single Point of Human Authority
@diega was the only person with merge access who cut releases. One community maintainer had a ready-to-merge PR (#649) but no merge rights. No governance path for security-critical changes without a non-reviewing approver.
Go Toolchain Lock-in
The fjl/memsize dependency was incompatible with Go 1.22+, locking the client to Go 1.21 (EOL August 2024). Three community PRs attempted partial fixes. The lock-in was known; it was not prioritized until it became a crisis.
Emergency Releases without Pre-release Testing
The v1.12.21 pull request was merged 70 minutes after it opened and the v1.12.22 pull request in under 2 minutes, each by its author and with no review recorded. The same process introduced the eth_syncing regression (issue #697, still open).
Attribution
Maintainers
Core-Geth is a fork of multi-geth, originally created and maintained by Wei Tang (@sorpaas). Multi-geth was the first multi-network go-ethereum fork with first-class ETC support, and its chain configuration architecture is the direct ancestor of core-geth.
The core-geth fork was then developed by ETC Labs until they left the ETC ecosystem in 2021. ETC Cooperative-paid staff maintained the client through the Spiral hard fork up until announcing maintenance mode for the client in December 2024:
- Isaac Ardis (@meowsbits) — primary architect and long-term maintainer
- Diego López León (@diega) — release manager; cut the v1.12.20 release
- Chris Ziogas (@ziogaschr) — contributor and maintainer
Current
The client is maintained in the ethereumclassic organization by the @ethereumclassic/core-developers team, which 85d68471d names as code owners across the consensus, networking, CI, licensing and documentation paths. Naming a team rather than an account is what keeps a reviewer available when any one person is not, which is the failure this report documents.
Upgrade
Upgrade Path
Core-Geth is maintained in the ethereumclassic organization, and that is where its releases are published. Run the current release and track that repository: a node watching the previous one will not see it.
If you run any v1.12.x release, upgrade to Core-Geth v1.13.0 or later and rotate your node key. Every v1.12.x release, v1.12.23 included, carries at least one unpatched CVE and was built on a Go version that left support in August 2024 or February 2025. The migration guide covers Linux, macOS, Windows and Docker, and needs no resync.
Upgrade now
Run the current Core-Geth release, and rotate the P2P node key as you go.
About twenty minutes of downtime. Your chain data carries over, so there is no resync.
Defaults
What Else Changed in v1.13.0
Two defaults changed with this release, for different reasons. One is a security posture taken against the state of the network these audits measured. The other follows from the condition behind the CVE gap itself: services the network relied on were run by one organization, whose board has communicated that it is winding down.
Security posture: MESS is on
v1.13.0 ships MESS (ECBP-1100) enabled on Ethereum Classic and Mordor, where the v1.12.x line disabled it. MESS changes which of two competing chains a node prefers, never whether a block is valid. --mess=false keeps the v1.12.x behavior. MESS, and which setting fits which operator
Peer discovery moved to the community organization
The bootnodes and DNS discovery trees compiled into v1.13.0 are published from ethereumclassic/discv4-dns-lists, in the community organization and on domains it holds. The lists the previous releases carried are the Cooperative's, are set to be archived as it dissolves, and this client does not hold their signing key. --bootnodes and --discovery.dns accept any other list. How the lists are built
The ETC Cooperative is winding down, and why that matters
The public RPC endpoint the ecosystem pointed at went offline in late August 2026 without notice, and anything holding it in configuration stopped working. A release whose discovery lists can disappear the same way carries that risk into every node running it. Where each service continues
The v1.13.0 release report covers every change and how to verify a download
Recommendations
Recommendations
Upgrade to the current Core-Geth release from ethereumclassic/core-geth, following the migration guide. Every v1.12.x release, v1.12.23 included, carries at least one unpatched CVE and an end-of-life Go toolchain. Nodes on v1.12.20 or earlier are exposed to remote crash (CVE-2026-26313, CVE-2026-22862) and potential key-oracle attacks (CVE-2026-26315).
Rotate the P2P node key after upgrading. It is a required step, because CVE-2026-26315 leaks bits of that key. With the node stopped, rename the key rather than deleting it; the node writes a new one on its next start, and its enode ID changes: mv <datadir>/geth/nodekey <datadir>/geth/nodekey.old-rotated-$(date +%F)
Treat the upgrade to v1.13.0 as a security-critical update, not a routine version bump. Upgrade one node first, confirm its head matches the rest, then move the remainder and rotate each node key as you go.
Run more than one node and compare their heads before acting on either reading. The clients page lists the implementations and the ETC execution plugins, so you can see what a second opinion could come from.
Keep the --graphql endpoint off on public-facing nodes until they run v1.13.0. No v1.12.x release adds the query depth limit.
Methodology
Methodology and Scope
The audit began during cross-client interoperability testing. It targeted etclabscore/core-geth at tag v1.12.20 (commit c2fb44129), cross-referenced against the go-ethereum security advisory database and the Go vulnerability database (vuln.go.dev). Each advisory was assessed by tracing the code core-geth shares with go-ethereum. Exploitability was confirmed for CVE-2026-22862, which was exploited; for the others, reachability from unauthenticated network input was established by reading the affected call paths. Fixes were cherry-picked from go-ethereum where possible, and ported by hand for CVE-2026-26313 and CVE-2026-26314, where the code had diverged. Tools: govulncheck, manual code review, the go-ethereum advisory database and vuln.go.dev.
Every patch was validated on the Mordor testnet: sync resuming after the patch, P2P handshake stability under normal peer traffic, unchanged JSON-RPC responses from eth_syncing, eth_blockNumber and net_peerCount, and block processing against known Mordor block hashes.
In scope
- Go packages inherited from go-ethereum with known CVE exposure
- The Go toolchain version and dependency security posture
- P2P input validation: devp2p, RLPx, eth and snap
- RPC endpoint security: GraphQL and JSON-RPC
Out of scope
- Consensus-layer correctness and ETC protocol compliance
- EVM execution correctness
- Dependencies not listed in the go-ethereum security advisory database
- Infrastructure: bootnode operators, DNS and CDN
References
References
- Core-Geth v1.13.0 release notes
- Core-Geth v1.13.0 release report
- v1.13.0: the record behind the release, answering published claims from commit metadata, pull requests and release files
- MESS: what v1.13.0 defaults to, and the trade-off per operator
- Migrating to v1.13.0
- March 2026 security audit: the six CVEs, per release, with the disclosure timeline
- September 2026 release-artifact audit: what the published archives contain, measured by opening them
- August 2026 security follow-up, covering v1.12.23
- Dependency and toolchain modernization
- Go toolchain: which toolchain built each archive, and the advisories each one carries
- The ETC Cooperative transition: where each service continues
- Release artifacts audit
- Reporting a vulnerability: SECURITY.md
- Security contact for pools, exchanges and service providers: security@ethereumclassic.com
- etclabscore/core-geth: the previous repository and the v1.12.x releases
- go-ethereum GitHub Security Advisories
- Go Vulnerability Database — vuln.go.dev
- ETC Node Clients
- Client Implementations
- ECIP-1112: Sovereignty Vault (draft) — where base-fee revenue would accumulate