Skip to main content
SECURITY AUDITMarch 2026 · follow-up August 2026

Core-Geth v1.12.x Security Audit

An audit of the Core-Geth v1.12.x release line, published from etclabscore/core-geth. It found six CVEs and a GraphQL denial of service left unpatched through a 21-month gap in security maintenance. Two of them, CVE-2026-22862 and CVE-2026-26315, were exploited against Ethereum Classic bootnodes in March 2026. Every v1.12.x release, v1.12.23 included, still carries at least one unpatched CVE and was built on a Go version that left support in August 2024 or February 2025. All of them are fixed in Core-Geth v1.13.0, released September 14, 2026 from ethereumclassic/core-geth.

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.

Audits

  • March 2026 security audit

    Six CVEs and a GraphQL denial of service in Core-Geth v1.12.x, with the per-release breakdown and the March 2026 attack on Ethereum Classic bootnodes.

  • August 2026 dependency modernization

    What changed underneath Core-Geth between the December 2024 archive point and v1.13.0: the Go toolchain, the module graph and the linter.

  • August 2026 security follow-up

    Core-Geth v1.12.23 measured at its tag against the advisory records: what it fixed, what it left open, and how its CVE identifiers reconcile.

  • September 2026 Go toolchain

    Which Go toolchain built each published Core-Geth archive, and the Go standard library advisories each v1.12.x archive carries that v1.13.0 does not.

  • September 2026 release artifacts

    What the published Core-Geth archives actually contain: platform floors, architectures and provenance, measured from the files themselves.

Reports

  • v1.13.0 release report

    What Core-Geth v1.13.0 fixes and changes, the files it publishes, and how to verify a download against its checksum and build attestation.

  • v1.13.0: the record behind the release

    Claims made about the Core-Geth v1.13.0 release, answered from the public record: commit metadata, pull requests, release files and advisory databases.

Affects v1.12.x6 CVEs5 HIGH severity21-month gapGo 1.21 and 1.22 EOLFixed in v1.13.0

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:921

Stack 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

June 10, 2024

Core-Geth v1.12.20 released at etclabscore/core-geth

Last release before a 21-month gap in security maintenance

August 2024

Go 1.21 reaches end-of-life

Build toolchain unsupported, runtime CVEs accumulate unpatched

January 23, 2025

Last upstream commit before the 2026 emergency releases: a GitHub Actions CI update

No code changes recorded in the period that follows

Throughout 2025

Security disclosures sent to upstream maintainer

No response recorded

February 4, 2026

Ledger security researcher publicly discloses three CVEs in issue #692

No maintainer response until March 18

Feb – Mar 2026

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

4 March 2026

Go toolchain upgraded 1.21 → 1.26

Commit b7d164018; blst v0.3.11 → v0.3.16

March 18, 2026

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

March 20–21, 2026

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

March 28, 2026

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

August 14, 2026

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

September 14, 2026

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.

v1.12.20 and earlier

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.

v1.12.21 "Aegis"

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.

v1.12.22 "Hermes"

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.

v1.12.23 "Argos"

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.

v1.13.0

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.

CVE-2025-24883HIGHFIXED IN 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

CVE-2026-22862HIGHFIXED IN v1.13.0

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

CVE-2026-26315HIGHFIXED IN v1.13.0

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

CVE-2026-26314HIGHFIXED IN v1.13.0

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

CVE-2026-26313HIGHFIXED IN v1.13.0

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.0

KZG 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.0

No 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

CRITICAL

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.

HIGH

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.

HIGH

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.

HIGH

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.

HIGH

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.

MEDIUM

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.

MEDIUM

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.

HIGH

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.

HIGH

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.

OPEN — never implemented

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.

OPEN — never merged

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.

CLOSED without merge

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.

CLOSED without merge

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.

OPEN — never merged

Automated: remove unresponsive bootnodes

Bootnode health check flagged deployed ETC bootnodes as unresponsive — some already experiencing intermittent crash-loops from early exploit probing.

CLOSED — no response for 42 days

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.

COMPLETE — public from 26 February

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.

MERGED — 70 minutes after opening

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.

COMPLETE — opened 20–21 March

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.

MERGED — under 2 minutes after opening

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.

OPEN — unresolved

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.

MERGED — no review recorded

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.

COMPLETE — every finding resolved

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.

1

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.

2

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.

3

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.

4

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.

5

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:

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

Node operators on any v1.12.x release

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).

All nodes

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)

Infrastructure providers & exchanges

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.

Multi-client operation

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.

GraphQL endpoints

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