Skip to content

deps: vuln cleanup (otel, chi, x/*, go-libp2p, fasthttp, ipld-prime, testcontainers, tooling) - #3094

Open
iurii-ssv wants to merge 14 commits into
deps/grpc-1.83.2from
deps/vuln-cleanup
Open

iurii-ssv wants to merge 14 commits into
deps/grpc-1.83.2from
deps/vuln-cleanup

Conversation

@iurii-ssv

@iurii-ssv iurii-ssv commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #3093 (grpc bump), which is stacked on #3071. Cleans up the remaining govulncheck findings that #3071 and #3093 leave open. One commit per dependency so each can be reverted alone, plus one network/p2p commit so the go-libp2p bump doesn't advertise our private addresses.

Dependency Version Clears Reachable?
OTel exporters + contrib otlptrace* 1.41.0 / otlpmetric* 1.36.0 / otlplog* 0.12.2 / autoexport 0.61.0 / prometheus exporter 0.58.0 / otelhttp 0.63.0 → 1.45.0 / 0.21.0 / 0.67.0 / contrib 0.70.0 (same release set as otel/sdk v1.45.0 from #3071) GO-2026-6505, GO-2026-4985, GO-2026-6508, GO-2026-6615; klauspost/compress 1.19.1 also clears GO-2026-5841 only when OTLP export is enabled (opt-in)
github.com/go-chi/chi/v5 5.2.2 → 5.3.2 GO-2026-5775, GO-2026-5777, GO-2026-4316, GO-2026-5774 (the last two were introduced by the 5.2.x line) no: RealIP / RedirectSlashes aren't used
ssvsigner: golang.org/x/{crypto,net,text} 0.52.0 / 0.54.0 / 0.37.0 → 0.55.0 / 0.58.0 / 0.41.0 (matches root) GO-2026-6303, GO-2026-5025..5030, GO-2026-5942, GO-2026-5970 5970 only: keystore password normalization, operator-supplied input
golang.org/x/crypto (root + ssvsigner) 0.55.0 → 0.56.0, plus go 1.26 → go 1.26.0 and toolchain go1.26.8 GO-2026-6354, GO-2026-6355 no: x/crypto/ssh isn't used
github.com/libp2p/go-libp2p 0.45.0 → 0.49.0 (quic-go 0.60.0, webtransport-go 0.11.1), plus pion/dtls/v3 3.1.4 and pion/stun/v3 3.1.5 GO-2025-4233, GO-2026-5676, GO-2026-4483, GO-2026-4485, GO-2026-4488, GO-2026-6099, GO-2026-6165, GO-2026-6163 no: our libp2p host is TCP-only (network/p2p/config.go), so QUIC/WebTransport/WebRTC never run
golang.org/x/mod 0.38.0 → 0.40.0 GO-2026-6179, GO-2026-6180 no: module-level only (we use modfile/module in ibft/storage test utils)
ssvsigner: github.com/valyala/fasthttp 1.58.0 → 1.70.0, plus klauspost/compress 1.18.0 → 1.19.1 (matches root) GO-2026-4950; GO-2026-5841 for the ssvsigner build no: the vulnerable symbols are fasthttp's file-serving functions, which we don't use
github.com/ipld/go-ipld-prime 0.21.0 → 0.23.0 GO-2026-5073, GO-2026-5684 no: imported via kad-dht/boxo IPNS, decoders never called
ssvsigner: go.opentelemetry.io/otel 1.41.0 → 1.45.0 (matches root), semconv import v1.39.0 → v1.43.0 GO-2026-5158 no
tools: mockgen (tool.mod) 0.5.2 → 0.6.0 aligns the generator with the gomock 0.6.0 runtime from the go-libp2p bump; regenerated mocks are byte-identical n/a
ssvsigner e2e: testcontainers-go 0.37.0 → 0.44.0, moby/go-archive 0.1.0 → 0.3.0; github.com/docker/docker replaced by github.com/moby/moby/{api,client} GO-2026-6253; dropping docker/docker also removes GO-2026-4883, 4887, 5617, 5668, 5746 (no upstream fix) e2e tests only

Heads-up: /metrics labels change

The OTel Prometheus exporter 0.67.0, which autoexport 0.70.0 requires, changes the exposition slightly. I diffed a scrape of representative ssv instruments before and after:

  • Metric names and suffixes (_total, _seconds, _bucket, ...) are unchanged.
  • Every series gains an otel_scope_schema_url="" label. This creates new series identities at upgrade time; name-based queries and dashboards keep working.
  • The separate otel_scope_info series is no longer emitted. Nothing in this repo references it.

The prometheus client_golang (1.23.2 → 1.24.1) and prometheus/common bumps come along with it.

Why the toolchain line

x/crypto 0.56.0 requires go ≥ 1.26.0, so go mod tidy rewrites go 1.26 to go 1.26.0. CI's actions/setup-go (go-version-file: go.mod) currently resolves 1.26 to the latest 1.26.x (1.26.8). With 1.26.0 it would install exactly 1.26.0. toolchain go1.26.8 keeps CI on the patched release; setup-go prefers the toolchain line when it's present.

go-libp2p 0.45 → 0.49: what I checked

The upstream release notes have no API breaks for the options we use (TCP transport, noise, ping, NAT service, AutoNAT rate limit). Behavior changes that touch our code:

  • Connected/Disconnected notifications moved into the swarm's event emitter (refactor(swarm): move the connected / disconnected callbacks into the events emitter libp2p/go-libp2p#3503). Ordering is unchanged:
    • Connected fires synchronously.
    • Disconnected is dispatched asynchronously, after the conn has been removed from the swarm, and never before Connected finished.
    • So conn_handler's Connectedness() check in DisconnectedF behaves as before.
  • AllAddrs() / Addrs() resolve 0.0.0.0 to every interface address since v0.48 (basichost: advertise all interface addrs for unspecified listen addrs libp2p/go-libp2p#3468). Before, only the default-route interface address was used.
    • Our own code only reads host.Addrs() for the my_address field of the "starting p2p" log line.
    • identify and the signed peer record advertise the same list, so peers see our other interface addresses too (docker bridges, VPN interfaces, ...). Our AddrsFactory only appended the HostAddress/HostDNS address and didn't filter.
    • Impact should be small. Discovery still dials ENR addresses, and the receiving side's identify keeps only public addresses when the connection comes in over a public IP (as in v0.45), so only peers on a shared private network store the extra private ones. A container on a single Docker network only has lo and eth0, so its list doesn't change; it's hosts with several interfaces (e.g. host networking) that advertise more.
    • With HostAddress/HostDNS set, the network/p2p commit now drops the non-public ones (see below).
  • Smaller hardening: identify bounds the number of protocols accepted from peers, and the peerstore caps unconnected addrs per peer.
  • Side bumps from MVS:
    • The gomock runtime moves to 0.6.0. mockgen in tool.mod follows in its own commit (see the table), and regenerating the mocks with it leaves them byte-identical.
    • zap 1.28.0, yamux 5.1.0, x/exp, and the multiformats/ipfs utility libs.

This is the riskiest commit here. Please give it an E2E run and some soak time on stage, watching peer counts, connection churn, and the addresses other nodes record for ours (/v1/node/peers).

Advertised addresses (network/p2p)

With HostAddress/HostDNS set, our AddrsFactory now keeps only the public addresses and appends the external one. identify, the signed peer record and my_address then carry just what peers can dial, and a private HostAddress is still announced.

  • Without HostAddress/HostDNS nothing changes: local clusters and private networks rely on the private addresses.
  • AutoNAT already filters the factory's output down to public addresses, and mDNS announces the interface listen addresses directly, so neither is affected.
  • v0.49's libp2p.NonPublicAddrPublishing(false) alone wouldn't do: it only covers the signed peer record, not identify's unsigned list.

fasthttp 1.58 → 1.70 (ssvsigner API server)

Header parsing became stricter (1.65: CRLF-only delimiters; 1.70: exactly one Host header, request-URI validation, CRLF sanitization in setters). The ssv node talks to ssvsigner through the net/http-based ssvsigner.Client, which sends compliant requests. To double-check, I ran a throwaway test that serves the real Server.Handler() over TCP with fasthttp 1.70 and calls it with ssvsigner.Client. List, identity, sign and remove all round-trip correctly. The test is not committed; the e2e suite covers this path in CI.

testcontainers-go 0.37 → 0.44 (ssvsigner e2e only)

No testcontainers release requires the fixed moby/go-archive (v0.44.0 still pins v0.2.0). Bumping go-archive on its own breaks docker/docker v28's pkg/archive, which testcontainers ≤0.41 uses. Since v0.42, testcontainers uses the moby/moby client modules, so this commit:

  • moves testcontainers-go to v0.44.0 and go-archive to v0.3.0;
  • switches e2e/testenv/containers.go to the container/mount/network types from github.com/moby/moby/api, replacing docker/docker and go-connections/nat. network.Port.Port() has the same semantics as nat.Port.Port().

I ran the ssvsigner e2e suite locally with a freshly built ssv-signer:latest image, i.e. make test-e2e with the image built from the repo root as in CI. All 4 tests (22 including subtests) pass: TestAttestationSlashing, TestBlockSlashing, TestValidatorRegistrationSigning, TestVoluntaryExitSigning.

Housekeeping

  • registry/storage/recipients.go: dropped the go:generate directive for mocks/recipients.go. That mock was never committed and has no users.
  • go.spec.alan.mod / .sum are reduced to the single require github.com/ssvlabs/ssv-spec v1.2.2 pin and its two go.sum lines.
    • Nothing is built against this file. make spec-test-alan only runs go mod download with it, and ibft/storage reads the ssv-spec version from it to locate the Alan vectors.
    • It can't be refreshed as a copy of the current go.mod. The ./ssvsigner replace requires the newer ssv-spec, so the first go mod download raises the pin to the main-line pseudo-version, and the Alan run then silently uses the wrong vectors. I hit exactly this, and TestQBFTMappingAlan failed with error-code and proposer mismatches.
    • The old file only worked because it froze an old ssvsigner too. The minimal file can't go stale, and the header comment explains why it only lists ssv-spec.
    • make spec-test-alan passes with it (qbft + ssv), and it resolves the same v1.2.2 artifact key as on stage.

Notes on the follow-up commits

  • go.sum grows by ~440 lines in the ipld-prime commit. Nearly all are /go.mod checksums from its larger module graph; only 7 are new module source hashes. ipld-prime 0.23.0 also requires a polydawn/refmt pseudo-version.
  • ssvsigner only uses semconv for HTTP attribute keys (http.request.method, http.response.status_code, http.route). They are identical in v1.39.0 and v1.43.0, so its metric attributes don't change. otelhttp and otel/sdk/metric only come in via the e2e testcontainers dependency, so the otel commit leaves them alone. The testcontainers move later takes otelhttp to v0.69.0 (indirect) and drops otel/sdk/metric from ssvsigner/go.mod (only otelhttp's own tests import it).
  • Regenerating every mockgen go:generate target with v0.6.0 leaves all committed mocks byte-identical.

Still open (no fix available)

  • kad-dht GO-2024-3218: no fix available.
  • x/crypto GO-2026-5932 (openpgp is unmaintained): no fix, and we don't import it.

Verification

  • go mod tidy makes no further changes (root and ssvsigner). Build, vet (including test files) and the full make lint pass. That covers golangci-lint for root and ssvsigner, deadcode, openapi and the ssvsigner import-boundary check.

  • Root unit tests (make unit-test package set, without -race/coverage): 76 packages pass. The only failures are three mDNS-based tests in network/p2p and network/topics. They fail the same way on unmodified stage in my local sandbox (multicast), and CI covers them. The pass/fail set is identical before and after each commit here.

  • ssvsigner unit tests pass, and the ssvsigner e2e suite passes locally (see above).

  • make spec-test-alan passes locally against the reduced go.spec.alan.mod.

  • observability/... passes, including deps: security bumps (x/crypto, otel/sdk, chi) #3071's TestBuildResources (semconv still matches) and /metrics scrape test. api/... and exporter/v1/api/... pass after the chi bump, and network/discovery passes after the ipld-prime bump.

  • network/p2p: TestConfig_AddrsFactory covers the filter (public and private HostAddress, HostDNS, neither) and fails without it. On a real v0.49 host with HostAddress set, h.Addrs() and the signed peer record carry only the external address; without it they list a VPN, the loopback and the LAN address. The rest of network/p2p fails only the same mDNS tests as before the commit.

  • govulncheck ./... on this branch (Go 1.26.8 via the toolchain line):

    • root: 87 findings on stage (41 reachable) → 2, both without an available fix (kad-dht GO-2024-3218, x/crypto openpgp).
    • ssvsigner: 67 → 1 (the same openpgp entry).
  • E2E passed - [action log](put link here)

@iurii-ssv
iurii-ssv requested review from a team as code owners October 7, 2026 11:11
@iurii-ssv
iurii-ssv added this pull request to stack #3095 October 7, 2026 11:11
@iurii-ssv
iurii-ssv removed this pull request from stack #3095 October 7, 2026 11:11
@iurii-ssv
iurii-ssv added this pull request to stack #3096 October 7, 2026 11:12
@greptile-apps

greptile-apps Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

[High risk] Updates Go dependencies across main and submodule.

This PR appears safe to merge; no actionable issue caused by its changes was found.

Summary

Updates OpenTelemetry exporters and related libraries, upgrades chi, and aligns the signer’s x/ modules with the root module.

  • Changes are limited to dependency requirements and checksums.
  • No actionable issue caused by these changes was established.
  • iurii-ssv explicitly acknowledged the added otel_scope_schema_url label and removed otel_scope_info series as intentional upgrade effects.
  • iurii-ssv explicitly deferred the libp2p transport upgrades for separate testing and x/crypto 0.56.0 for a separate Go toolchain decision.
  • Builds and tests were not run during this review.

Reviews (1) · Last reviewed commit: "deps(ssvsigner): bump golang.org/x/{cryp..." · Reviewed by Greptile

@codecov

codecov Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 66.6%. Comparing base (3ba8990) to head (6a58109).

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@iurii-ssv iurii-ssv changed the title deps: align otel exporters, bump chi and ssvsigner x/ modules deps: vuln cleanup (otel exporters, chi, x/crypto, go-libp2p, ssvsigner x/) Oct 7, 2026
@iurii-ssv iurii-ssv changed the title deps: vuln cleanup (otel exporters, chi, x/crypto, go-libp2p, ssvsigner x/) deps: vuln cleanup (otel, chi, x/*, go-libp2p, fasthttp, ipld-prime, mockgen) Oct 7, 2026
@iurii-ssv iurii-ssv changed the title deps: vuln cleanup (otel, chi, x/*, go-libp2p, fasthttp, ipld-prime, mockgen) deps: vuln cleanup (otel, chi, x/*, go-libp2p, fasthttp, ipld-prime, testcontainers, tooling) Oct 7, 2026
momosh-ssv
momosh-ssv previously approved these changes Oct 8, 2026
Comment thread tool.mod
Comment thread ssvsigner/go.mod
Comment thread go.mod
@iurii-ssv
iurii-ssv dismissed momosh-ssv’s stale review October 13, 2026 13:08

The merge-base changed after approval.

@momosh-ssv
momosh-ssv removed this pull request from stack #3096 October 15, 2026 07:36
otel/sdk moved to v1.45.0 but the exporters stayed on older release
sets (otlptrace* v1.41.0, otlpmetric* v1.36.0, otlplog* v0.12.2,
autoexport v0.61.0, prometheus exporter v0.58.0, otelhttp v0.63.0).
Move all of them to the v1.45.0 / v0.21.0 / v0.67.0 / contrib v0.70.0
release set. Clears GO-2026-6505 (otlptrace*), GO-2026-4985
(otlptracehttp), GO-2026-6508 (otlploggrpc), GO-2026-6615 (sdk/log);
the klauspost/compress bump that comes along also clears GO-2026-5841.

Visible on /metrics: the prometheus exporter no longer emits the
otel_scope_info series and adds an otel_scope_schema_url label to every
series. Metric names and their suffixes are unchanged.
v5.2.2 is still affected by GO-2026-5775/GO-2026-5777 and newly by
GO-2026-4316 (RedirectSlashes) and GO-2026-5774 (RealIP), all fixed in
v5.3.0. None of these middlewares are used (api/server only uses
Throttle, Compress and NewWrapResponseWriter), so this is scanner
hygiene; behavior changes in the middlewares we do use are limited to a
Throttle fast path and a WrapResponseWriter byte-count fix.
ssvsigner builds its own binary from its own go.mod, so the root bumps
do not reach it. Move x/crypto v0.52.0 -> v0.55.0, x/net v0.54.0 ->
v0.58.0 and x/text v0.37.0 -> v0.41.0 (same versions the root module
resolves to). Clears GO-2026-6303, GO-2026-5025..5030, GO-2026-5942 and
GO-2026-5970; the latter is on a reachable path (keystore password
normalization during decrypt), though the input is operator-supplied.
x/crypto v0.56.0 clears GO-2026-6354/GO-2026-6355 (x/crypto/ssh, not
used by the shipped binaries). It requires go >= 1.26.0, so the go
directive moves from "go 1.26" to "go 1.26.0" in both modules.

On its own that would make actions/setup-go (go-version-file: go.mod)
install exactly 1.26.0 instead of resolving "1.26" to the latest 1.26.x
(currently 1.26.8). Add "toolchain go1.26.8" so CI keeps building and
testing with the patched release; local builds with an older Go switch
to it automatically (GOTOOLCHAIN=auto). Docker builds are unaffected:
the official golang images set GOTOOLCHAIN=local.
v0.49.0 is the first go-libp2p release on quic-go v0.60.0 and
webtransport-go v0.11.1, which clear GO-2025-4233, GO-2026-5676 and
GO-2026-4483/4485/4488/6099; pion/dtls/v3 v3.1.4 and pion/stun/v3 v3.1.5
are bumped explicitly for GO-2026-6165 and GO-2026-6163. None of these
are reachable: our libp2p host only configures the TCP transport.

Upstream behavior changes that touch our code:
- Connected/Disconnected notifications moved into the swarm's events
  emitter; ordering is unchanged (conn removed from the swarm before
  Disconnected fires asynchronously, never before Connected finished),
  so conn_handler's Connectedness check in DisconnectedF still holds.
- Addrs()/AllAddrs() list all interface addresses when listening on
  0.0.0.0; we only use host.Addrs() for the "starting p2p" log line.

MVS also moves the gomock runtime to v0.6.0 (mockgen in tool.mod stays
at v0.5.2; existing generated mocks compile and pass), zap v1.28.0,
yamux v5.1.0, x/exp and multiformats/ipfs utility libs.
Clears GO-2026-6179/GO-2026-6180 (x/mod/sumdb, module-level only: we
only use x/mod/modfile and x/mod/module in ibft/storage test utils).
Pulls x/tools v0.49.0 and a newer x/telemetry along.
Clears GO-2026-4950 (ServeFile/ServeFS path decoding). Not reachable:
ssvsigner only uses fasthttp as its API server and serves no files.
Also moves klauspost/compress v1.18.0 -> v1.19.1 to match root, which
clears GO-2026-5841 for the ssvsigner build.

Header parsing is stricter since v1.65/v1.70 (CRLF-only delimiters,
exactly one Host header, URI format validation); the node's
net/http-based ssvsigner client round-trips fine against it.
Clears GO-2026-5073 and GO-2026-5684 (DAG-CBOR/DAG-JSON decoder
allocation and recursion limits). Indirect via go-libp2p-kad-dht /
boxo's IPNS support; the decoders are imported but never called.
ipld-prime v0.23.0 requires a newer polydawn/refmt pseudo-version.
Moves ssvsigner's otel, otel/metric and otel/trace from v1.41.0 to
v1.45.0 (clears GO-2026-5158, baggage header length cap) and the
semconv import to v1.43.0, matching the root module. ssvsigner only
uses semconv for HTTP attribute keys (no resource merge), and the keys
it uses keep the same names. otelhttp and otel/sdk/metric stay as they
are: they only come in via the e2e testcontainers dependency.
The go-libp2p bump moved the go.uber.org/mock runtime to v0.6.0 while
mockgen in tool.mod stayed at v0.5.2. Align the generator with the
runtime. Regenerating all mockgen go:generate targets with v0.6.0
produces byte-identical mocks, so no generated files change.
The go:generate directive in recipients.go targets mocks/recipients.go,
which was never committed and has no users; running go generate only
produced an untracked, unused file.
…ve v0.3.0

moby/go-archive v0.3.0 fixes GO-2026-6253 (tar extraction outside the
target directory), but no testcontainers-go release requires it (v0.44.0
still pins v0.2.0), and bumping it on its own breaks
docker/docker v28's pkg/archive. testcontainers-go v0.42+ moved from
github.com/docker/docker to the github.com/moby/moby/{api,client}
modules, so:

- testcontainers-go v0.37.0 -> v0.44.0 and moby/go-archive -> v0.3.0
- e2e/testenv: import container/mount/network types from
  github.com/moby/moby/api instead of docker/docker and go-connections

This drops github.com/docker/docker from ssvsigner entirely, which also
removes its no-fix advisories (GO-2026-4883, GO-2026-4887,
GO-2026-5617, GO-2026-5668, GO-2026-5746). All of this is e2e-only.
go.spec.alan.mod was a frozen copy of an old go.mod (go 1.24.6, grpc
1.75, otel 1.38, ...), but nothing is built against it: make
spec-test-alan only runs go mod download with it and
ibft/storage reads the ssv-spec version from it to locate the Alan
vectors. Only the ssv-spec requirement matters.

It cannot be refreshed as a copy of the current go.mod: the
./ssvsigner replace requires a newer ssv-spec, so the go command raises
the pin to the main-line pseudo-version on the first go mod download and
the Alan run silently uses the wrong vectors. Keep only
`require github.com/ssvlabs/ssv-spec v1.2.2` (and its two go.sum lines),
which also cannot go stale. make spec-test-alan passes and resolves the
same v1.2.2 artifacts as before.
@momosh-ssv
momosh-ssv added this pull request to stack #3123 October 15, 2026 07:40
@iurii-ssv
iurii-ssv requested a review from momosh-ssv October 15, 2026 09:07
Since go-libp2p v0.48 the 0.0.0.0 listen address resolves to every
interface address instead of only the default-route one, and identify
and the signed peer record advertise what our AddrsFactory returns. The
factory only appended the HostAddress/HostDNS address, so peers got our
docker bridge, VPN and other private interface addresses too.

With an external address configured, peers reach us through it (it's
what our ENR carries), so the factory now keeps only the public
addresses and appends the external one; a private HostAddress is still
announced. The my_address field of the "starting p2p" log line shows
the same list. Without HostAddress/HostDNS nothing changes, as local
clusters and private networks rely on the private addresses.

AutoNAT already filters the factory's output down to public addresses,
and mDNS announces the interface listen addresses directly, so neither
is affected.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants