Bee v2.8.2 is a security-hardening release focused on making nodes resilient against untrusted or corrupted input. There are no breaking P2P protocol changes, and nodes on v2.8.1 can upgrade at any time without network-wide coordination. The core of the release is a set of fixes that stop malformed peer messages, corrupted local state, and misbehaving RPC providers from crashing the node — every one of these was an availability problem, since a node that panics stops serving and syncing chunks, drops its peer connections, and cannot take part in a redistribution round while it is down. All node operators are encouraged to upgrade promptly.
📖 Read the release announcement on the Swarm blog.
💬 Join us on Discord (#node-operators) if you have questions or feedback!
Important
📢 Upgrade notes
- Tracing moved to OpenTelemetry — Jaeger/OpenTracing support has been replaced with OpenTelemetry (OTLP export). If you have tracing enabled, point
tracing-endpointat an OTLP-capable collector and review the newtracing-protocol,tracing-insecure,tracing-ca-fileandtracing-sampling-ratiooptions. With tracing disabled, nothing changes. - Tighter data-directory permissions — the state store and stamper store directories are now created with mode
0700, and files written by the node use0600. Existing directories are not modified, but external tooling that reads the data directory as another user may need adjusting. - Recovered panics are now logged — background workers recover panics instead of exiting the process. If you collect structured logs, these events are worth alerting on: a recovered panic still points at a bug worth reporting.
Security Hardening
Untrusted data can no longer crash the decoder
Bee decodes data that arrives from other nodes, and until now several decoders trusted the length fields inside that data:
- Manifest decoding — When parsing a Mantaray manifest, a single attacker-controlled byte declares how wide the references in that node are. A crafted value could point past the end of the actual payload, and both the reference slice and the trailing fork index would read out of bounds and panic the process. The decoder now checks the buffer length against the declared size and the fork offsets, and returns a malformed-manifest error instead. (7e703f4)
- File assembly — The joiner now bounds-checks leaf chunk reads and returns a malformed-trie error when a chunk's metadata advertises a span that cannot be real, rather than slicing out of bounds. (#5524)
- Chunk storage locations — Sharky's location records were unpacked directly by byte offset with no size check, and a shard index larger than the number of shards would slice past the end of the shard array. Both are now validated, returning a shard-not-found error. The recovery paths that rebuild storage after an unclean shutdown bounds-check the shard index too, so a corrupted on-disk location record cannot panic the very process meant to repair it. (7e703f4)
- Namespace lengths in the local store — In the chunkstamp and stampindex decoders, a crafted length prefix took advantage of a signed conversion: an enormous unsigned value became a small negative number, slipped past the length comparison, and then panicked when used to allocate. Negative lengths are now rejected outright. (7e703f4)
Malformed responses from the chain
When a smart contract call reverts, Bee reads the returned revert data to work out why. It assumed that data was always at least four bytes long — true of a well-behaved RPC provider, not guaranteed of a misbehaving or overloaded one. An empty or truncated response caused a panic while the node was buying a postage batch, topping one up, depositing stake, or claiming a redistribution win — exactly the moments an operator can least afford a crash. Bee now checks the length first and falls back to reporting the original error. (7e703f4)
Corrupted and null local state
A state store entry holding a literal JSON null decodes into a nil pointer without producing an error, so the code that read it dereferenced nothing and crashed. Three separate paths are now guarded:
- Reading or receiving a cheque from the chequebook store now returns a no-cheque error instead of dereferencing. (7e703f4)
- A peer that sends a JSON
nullbody as a cheque payload over the SWAP protocol is now rejected before the node touches the beneficiary field. (7e703f4) - A corrupted addressbook record with a nil address is now removed and reported as not found. (#5534)
Data races and resource leaks
- Price oracle — The background loop that refreshes the exchange rate and deduction wrote to those fields while API and settlement callers were reading them, with no synchronization. Reads and writes are now held under a mutex. (7e703f4)
- Failed uploads — When a file upload failed partway through the split, the background copier goroutine stayed blocked writing into a pipe nobody would read again, leaking a goroutine and a pipe on every failure. The pipe can now be closed from the read side, which unblocks the copier and waits for it to exit. (7e703f4)
- Shutdown — The pushsync and retrieval services run background loops, but their closers were never registered in the node's shutdown sequence, so those loops outlived the stop. Both are now shut down properly. (7e703f4)
A backstop for the rest
Individual guards only cover the paths someone thought to guard. This release also adds an internal panic recovery helper used to wrap background goroutines and worker loops across retrieval, salud, replicas, storage incentives, the storer, and transaction handling. A panic in one of those workers is now recovered and logged with context instead of taking the whole node down. (#5528)
Tighter on-disk permissions
The state store and stamper store directories are now created with mode 0700, files written by the node (sharky dirty markers, bee split output) use 0600, and the Docker image restricts the .bee data directory to the bee user. (7e703f4)
New Features
- OpenTelemetry tracing — Tracing migrated from OpenTracing/Jaeger to OpenTelemetry with OTLP export, including span kinds for clearer client/server semantics in trace views. (#5456, #5526)
- Light node limit option — New
--light-node-limitCLI flag and config option to control the maximum number of light node connections. (#5559) - Pullsync rate metric — The puller now exposes a pullsync rate metric for better observability of historical syncing. (#5552)
- Address book pruning — Stale address book entries are now pruned by last-seen time, keeping the address book bounded and fresh. (#5513)
- Protocol versioning groundwork — Peer protocol versions are now exposed and per-version protocol handlers are supported, laying the groundwork for smoother backward-compatible protocol upgrades. (#5539, #5548)
Bug Fixes
HEAD /bytesheaders — Entity headers onHEAD /bytes/{reference}responses are now correct. (#5551)- Handshake connection cleanup — Handshake error handling now uses precise connection cleanup instead of tearing down more than it should. (#5330)
Maintenance
- Postage snapshot — Updated the postage snapshot to v0.0.9. (#5575)
- OpenAPI — Bumped the API version in the OpenAPI spec. (#5574)
- Dependency upgrades — golang.org/x/net 0.55.0, golang.org/x/crypto 0.52.0, google.golang.org/grpc 1.82.1, quic-go/webtransport-go 0.11.1, pion/dtls 3.1.4, pion/stun 3.1.5. (#5523, #5529, #5547, #5549, #5554, #5553)
- CI — Linux Go tests moved to self-hosted runners, codecov-action bumped to v7, k3s bumped in beekeeper workflows, auto-assign and Swarm CLI version-bump automation improvements, kademlia test deflaking. (#5453, #5569, #5555, #5533, #5536, #5508)
What's Changed
- feat(tracing): migrate from OpenTracing/Jaeger to OpenTelemetry by @martinconic in #5456
- fix(joiner): add bounds checking on leaf reads by @janos in #5524
- chore(deps): bump golang.org/x/net from 0.52.0 to 0.55.0 by @dependabot[bot] in #5523
- test(kademlia): deflake TestAddressBookQuickPrune and TestOutofDepthPrune by @martinconic in #5508
- ci(auto-assign-author): skip bot/agent PR authors by @darkobas2 in #5533
- refactor(libp2p): use precise connection cleanup in handshake error handling by @gacevicljubisa in #5330
- chore(deps): bump golang.org/x/crypto from 0.51.0 to 0.52.0 by @dependabot[bot] in #5529
- fix(addressbook): validate address entries to prevent nil dereference by @akrem-chabchoub in #5534
- ci: auto-bump Bee version in Swarm CLI on stable release by @darkobas2 in #5536
- feat(tracing): add telemetry span kind by @gacevicljubisa in #5526
- feat(p2p): expose peer protocol version for backward compatibilities by @janos in #5539
- feat(addressbook): prune stale entries by last-seen time by @martinconic in #5513
- chore(deps): bump github.com/quic-go/webtransport-go from 0.10.0 to 0.11.1 by @dependabot[bot] in #5549
- chore(deps): bump google.golang.org/grpc from 1.80.0 to 1.82.1 by @dependabot[bot] in #5547
- chore(deps): bump github.com/pion/dtls/v3 from 3.1.2 to 3.1.4 by @dependabot[bot] in #5554
- chore(deps): bump github.com/pion/stun/v3 from 3.1.1 to 3.1.5 by @dependabot[bot] in #5553
- feat: add safe package for unified goroutine recovery by @janos in #5528
- feat(puller): add pullsync rate metric by @akrem-chabchoub in #5552
- feat(p2p): add versioned handlers function by @janos in #5548
- fix(api): bytes head entity headers by @gacevicljubisa in #5551
- ci: bump k3s to v1.35.6 in beekeeper workflows by @gacevicljubisa in #5555
- feat(cmd): add --light-node-limit CLI and config option by @martinconic in #5559
- ci: bump codecov-action to v7.0.0 to fix GPG verification failure by @darkobas2 in #5569
- ci: move Linux Go tests to self-hosted runners by @darkobas2 in #5453
- chore(openapi): bump api version by @acud in #5574
- chore: update postage snapshot to v0.0.9 by @gacevicljubisa in #5575
- fix(all): codebase hardening to improve protocol and code safety by @acud in 7e703f4
Full Changelog: v2.8.1...v2.8.2