Core-Geth Security Follow-Up: August 2026
- Follows:
2026-03-security-audit.md - Subject:
etclabscore/core-gethv1.12.23 (“Argos”), released August 14, 2026 - Prepared by: The core-geth Authors
- Agentic auditing methods and tooling: the strongest available Claude models at each stage of the work, February through September 2026
- Work carried out by: White B0x
- Work funded by: Ethereum Classic DAO
- Method: direct measurement against
etclabscore/core-gethat tagv1.12.23, and against the advisory records at OSV and the GitHub Advisory Database - Last edited: October 12, 2026
What operators need to do
Track releases at ethereumclassic/core-geth
and upgrade to v1.13.0 or later. Every finding in this document and in the
March 2026 audit is resolved there.
v1.12.23 is real security work, and it does not close the two findings that matter most to a node operator:
- The Go toolchains are still Go 1.21 and, for the Arm archives, Go 1.22, twenty-four and eighteen months past end of life. Every node built from any v1.12.x release, including this one, carries whatever runtime vulnerabilities have accumulated since, independent of the client’s own code. Go toolchain lists the standard library advisories.
- The
eth_syncingregression introduced in v1.12.22 is untouched. #697 reportshighestBlockincorrectly against the network head, which misleads exchanges, explorers and monitoring that read it to decide whether a node is synced. - One response cap in this release can disconnect peers that are answering correctly. The release corrects that class of error for account ranges and leaves it in place for storage ranges; see the finding below.
- Its release notes carry no advisory identifiers, like v1.12.21’s, and v1.12.22’s notes attach CVE-2026-26315 to work the records assign to CVE-2026-26314.
The organization that owns the repository has published that it does not expect to continue this work. Its 2024 retrospective states:
“Without any way to obtain funding, the ETC Coop will be in maintenance mode, with spending minimized, until the funding runs out. At that time, it will be up to other stakeholders to take on any required maintenance of the ETC client, unless a new plan materializes.”
v1.13.0 is that continuation, developed in the open at ethereumclassic/core-geth. It carries the Go 1.26 toolchain, every CVE fix, the same p2p hardening
series measured here, and the storage-range correction this release does not make.
Summary
A third release has been cut at etclabscore/core-geth since the March 2026 audit.
v1.12.23 is substantive security work: 32 commits carrying a delayed-decoding hardening
series for the p2p protocols, plus seven go-ethereum backports.
Two findings from the March audit are unchanged by it. The client remains on end-of-life Go
toolchains: Go 1.21, now 24 months past, and Go 1.22 for the Arm archives, now 18 months past.
The eth_syncing regression
introduced in v1.12.22 is not addressed.
This document records what v1.12.23 contains, what it leaves open, and where v1.13.0 stands.
Status by release
This is the per-release picture across the three axes a node operator needs: the client’s own CVEs, the Go toolchain each archive was built with, and the regressions each release introduced. It is why “the latest v1.12.x is patched” does not hold. Every v1.12.x release, v1.12.23 included, leaves at least one client-side issue open, and every one stands on an out-of-support Go toolchain.
| Finding | Severity | v1.12.20 | v1.12.21 | v1.12.22 | v1.12.23 | v1.13 line |
|---|---|---|---|---|---|---|
CVE-2026-22862: ECIES decrypt length (remote crash; exploited on the Core-Geth v1.12 bootnodes, March 2026) |
High | open | fixed | fixed | fixed | fixed |
| CVE-2026-26315: ECIES GenerateShared accepts an unvalidated key (node-key oracle) | Medium | open | fixed | fixed | fixed | fixed |
| CVE-2025-24883: off-curve point in UnmarshalPubkey | High | open | open | fixed | fixed | fixed |
| CVE-2026-26314: secp256k1 coordinate field-boundary bypass | High | open | open | fixed | fixed | fixed |
| CVE-2026-26313: P2P RLP item-count memory exhaustion | High | open | open | partial | fixed | fixed |
| CVE-2026-22868: KZG proof-verification DoS (not reached on ETC; active on the Ethereum Foundation networks the client also ships) | Medium | open | open | open | open | fixed |
| GraphQL query-depth DoS (endpoint off by default) | Medium | open | open | open | open | fixed |
| Go toolchain in support | - | no | no | no | no | yes |
| Go standard library advisories, all archives | - | 75 | 75 | 75 | 75 | 0 (go1.26.9) |
eth_syncing highestBlock regression (#697) |
- | not present | not present | introduced | present | not present |
| Snap storage-range cap can disconnect honest peers | - | not present | not present | not present | present | not present |
Legend: fixed means the fix is present; open means not addressed; partial means the crash is prevented and a related denial of service remains.
v1.12.22, the release most often described as the CVE backport, did not close every finding. It
fixed four of the six client CVEs and partly mitigated a fifth: CVE-2026-26313’s out-of-memory crash is
prevented, but a peer can still make the node spend CPU on a message it will reject. It did not address
the KZG denial of service or add the GraphQL depth limit, it introduced the eth_syncing regression,
and it stayed on Go 1.21 and Go 1.22.
v1.12.23 carries the delayed-decoding hardening that closes CVE-2026-26313, and adds the
storage-range cap in the row above. It does not touch the KZG path, the GraphQL limit, the
eth_syncing regression or the toolchain.
None of the three emergency releases recommend rotating the P2P node key. The node-key oracle
(CVE-2026-26315) they patch is the reason a node that ran v1.12.20 must rotate, so a patched node that
kept its key is still running an exposed one. The
March audit gives the procedure.
The Go standard library figure is the cross-archive union against the current database, 67 to 73 per archive. The v1.13.0 archives were built with go1.26.8 and carried none when the release shipped; the October 2026 Go batch has since reached go1.26.8 at module level, and v1.13.1 is built on go1.26.9, a scan of which reports none. The difference the table records is support: the v1.12.x toolchains will never receive any of these fixes. Go toolchain measures all of it.
What v1.12.23 contains
Measured across v1.12.22..v1.12.23: 32 commits, 71 files, +3,036 / -796 lines.
Delayed-decoding series. The release defers decoding of p2p message contents until after the message has been validated, so a peer cannot force allocation proportional to a claimed item count before anything has checked it:
| Commit | Change |
|---|---|
b25f25cf1 |
rlp: add RawList for working with un-decoded lists |
887da91c6 |
delay block body decoding until content validation |
717942ef3 |
delay receipts decoding until content validation |
de544c0c3 |
delay transaction packet decoding |
4a2b0effc |
delay snap message decoding |
4cdebb034 |
delay propagated block decoding until content validation |
4a8cd33ea |
discard message before size check |
0f8924182 |
validate responses against pending requests in p2p/tracker |
ff7d98f1a |
fix crash in p2p/tracker clean when the tracker is stopped |
85ac4d685 |
recalibrate snap account-range response item cap |
Upstream backports. Seven changes from go-ethereum: #34787 (stop serving on
unavailable responses), #34745 (drop peers sending invalid bodies or receipts), #34870
(batch index in deliver reconstruct), #34976 (snap error message), #33803 (embedded
node size validation), #32210 (announcement drop logic), #30918 (prevent hanging
dispatch).
The delayed-decoding refactor is adaptable to core-geth. go-ethereum’s rlp.RawList
approach does not cherry-pick cleanly onto this codebase (13 merge conflicts), and
v1.12.23 shows it can nonetheless be carried across with manual work.
What v1.12.23 does not change
The Go toolchains are unchanged and remain end-of-life. Measured at tag v1.12.23:
| Location | Value |
|---|---|
go.mod |
go 1.21 |
.github/workflows/test-linux.yml |
go-version: '1.21' |
Dockerfile |
FROM golang:1.22-alpine |
build/checksums.txt |
version:golang 1.22.1 |
The published archives record what built them: go1.21.13 for Linux x86_64, macOS
and Windows, and go1.22.1, the build/checksums.txt pin, for every Arm archive. Go 1.21
reached end-of-life in August 2024 and Go 1.22 in February 2025, and neither receives security
patches. Every node built from this release inherits whatever unpatched runtime vulnerabilities
its toolchain carries, independent of the client’s own code. This was the March audit’s finding
and it is unchanged across all three 2026 releases.
The eth_syncing regression is not addressed. Issue
#697, introduced in v1.12.22, reports
highestBlock as incorrect relative to the network head. No commit in
v1.12.22..v1.12.23 touches internal/ethapi/.
The cryptographic fixes from v1.12.21 and v1.12.22 are present and unchanged. Verified at tag: the
ECIES public-key validation in GenerateShared, which v1.12.21 added, and the field-boundary check in
crypto/secp256k1/curve.go, which v1.12.22 added, are both in place and byte-identical to this project’s own
implementation.
Finding: one response cap in v1.12.23 can still reject honest peers
v1.12.23 recalibrates the AccountRange item cap and documents why: the previous value
rejected honest responses. snapResponseLimits now reads
AccountRangeMsg: 2*maxRequestSize/common.HashLength + 1, // 32769
StorageRangesMsg: maxCodeLookups * 10, // 10240
ByteCodesMsg: maxCodeLookups, // 1024
TrieNodesMsg: maxTrieNodeLookups, // 1024
with a comment deriving the AccountRange figure from the request tracker’s byte bound.
StorageRanges is bounded the same way and did not get the same treatment. Reading
ServiceGetStorageRangesQuery at that tag, the server appends slots until size >= req.Bytes,
with a hardLimit of req.Bytes * (1 + stateLookupSlack) above it. Neither is an item count.
A storage slot costs a hash plus its value, so at least 33 bytes on the wire, and a 512 KiB
budget therefore admits on the order of 15,900 slots before the byte bound stops the
server, against a cap of 10,240.
The two caps that remain item-derived are correct: ByteCodesMsg and TrieNodesMsg are
genuinely capped server-side at maxCodeLookups and maxTrieNodeLookups, so those numbers
are the honest maximum.
Consequence. A peer answering a large storage-range request with small slots can exceed the cap without doing anything unusual, and is disconnected. This is the failure the AccountRange recalibration was made to fix, in the message type beside it.
This client carries no snap item ceiling at all. A response is matched against the pending request that produced it, in bytes for the two byte-bounded messages and in item count for the other two, so the bound is whatever was actually asked for. That cannot refuse an honest reply, which is the failure a fixed cap produces.
CVE identifier reconciliation
The advisory records assign these identifiers, verified against OSV and each fix commit confirmed in a full-history go-ethereum clone:
| Identifier | Issue | Fix commit | First release |
|---|---|---|---|
| CVE-2026-26313 · GHSA-689v-6xwf-5jf3 · GO-2026-4508 | p2p message memory exhaustion (CWE-770) | go-ethereum #33835 |
v1.17.0 |
| CVE-2026-26314 · GHSA-2gjw-fg97-vg3r · GO-2026-4507 | secp256k1 coordinate check (CWE-20) | 895a8597c |
v1.16.9 |
| CVE-2026-26315 · GHSA-m6j8-rg6r-7mv8 | ECIES public key validation in the RLPx handshake | 46bee92f9 |
v1.16.9 |
etclabscore/core-geth labels the secp256k1 issue CVE-2026-26315. That identifier belongs
to the ECIES handshake issue. The correct identifier for the coordinate check is
CVE-2026-26314. The label appears in commit 46bba8dfc, a doc comment and the Go test function
name TestIsOnCurveRejectsCoordinatesAboveP_CVE_2026_26315 in crypto/secp256k1/curve_cve_test.go,
the description of PR #696, the published
release notes for v1.12.22, and a
reply on issue #692.
No commit, source file, pull request description or release note there uses CVE-2026-26314; that
reply does, giving it to the ECIES fix in v1.12.21. The v1.12.21 and v1.12.23 notes carry no CVE
identifiers.
Why this is easy to get wrong, and why it matters. CVE-2026-26313 and CVE-2026-26314 are
published under the same title, “Go Ethereum affected by DoS via malicious p2p message”. They
are distinguished by CWE class and fix commit, not by their titles. An operator matching
advisory identifiers against release notes to decide whether they are exposed will not find
CVE-2026-26314 addressed at etclabscore/core-geth, and may conclude it is outstanding when the
underlying fix shipped in v1.12.22. Both issues are in fact addressed there.
Status of v1.13.0
v1.13.0 is released from
ethereumclassic/core-geth, the repository
created on December 21, 2024 under the GitHub organization that also hosts the ECIP
repository. It is where contributions and release artifacts for this series belong. ETC
Cooperative’s 2024 retrospective
records that with the organization in maintenance mode, “it will be up to other stakeholders to
take on any required maintenance of the ETC client”. Relative to
v1.12.23 it carries the Go 1.26 toolchain upgrade and the dependency graph that requires, the
six CVE patches with their tests, ETC network tooling, and the p2p hardening series. It is
the current release series. It has about six months of testing on Ethereum Classic mainnet and
Mordor behind it and a month in production since release, with no critical issue found.
Recommendation for operators is unchanged in direction and updated in target. Nodes on
any v1.12.x release should upgrade to v1.13.0 from ethereumclassic/core-geth immediately.
v1.12.23 is a safer position than v1.12.20 on both the cryptographic and p2p surfaces, and it
does not resolve the toolchain exposure.
Supporting this work
The client is maintained by Ethereum Classic’s core developers and open community contributions, in
the ethereumclassic GitHub organization. The Ethereum Classic
DAO is the legal entity standing behind that work, and the floor under it when nobody else is paying.
Mining pools, centralized exchanges, issuers of Ethereum Classic financial products, Etchash mining
hardware manufacturers and large holders all depend on this client. If your operation relies on
Ethereum Classic, please consider sponsoring its maintenance. Support this work says
who maintains and funds it and how to sponsor it.