v2.12.6

nats-io/nats-serverv2.12.6Mar 24, 2026by github-actions[bot]

AI Summary

A security and bug fix release addressing multiple CVEs and fixing various protocol compliance and JetStream issues, including a regression regarding consumer loss in clustered setups.

Key Highlights

  • Fixes for multiple CVEs affecting MQTT, Leafnodes, WebSockets, and JetStream
  • Added 1MB size limit on JWTs
  • Improved MQTT protocol compliance and session handling
  • Fixed stream update consumer loss regression introduced in v2.12.5
  • Fixed Raft log entry handling and stream restore performance

Full Release Notes

## Changelog

Refer to the [2.12 Upgrade Guide](https://docs.nats.io/release-notes/whats_new/whats_new_212) for backwards compatibility notes with 2.11.x.

### Go Version

- 1.25.8

### Dependencies

- golang.org/x/crypto v0.49.0 (#7953)
- github.com/nats-io/jwt/v2 v2.8.1 (#7960)
- golang.org/x/sys v0.42.0 (#7923)
- golang.org/x/time v0.15.0 (#7923)

### CVEs

- Fixes CVE-2026-33216, CVE-2026-33217, CVE-2026-33215 (affecting systems using MQTT)
- Fixes CVE-2026-33246 (affects systems using leafnodes and service imports)
- Fixes CVE-2026-33218 (affects systems using leafnodes)
- Fixes CVE-2026-33219 (affects systems using WebSockets)
- Fixes CVE-2026-33223, CVE-2026-33222 (affects systems using JetStream)
- Fixes CVE-2026-33248 (affects systems using mutual TLS)
- Fixes CVE-2026-33247 (affects systems providing credentials on the command line)
- Fixes CVE-2026-33249 (affects systems where client publish permissions should be restricted)

### Changed

General

- There is now a 1MB size limit on JWTs (#7960)

### Improved

General

- Non-WebSocket leafnode connections can now be proxied using HTTP CONNECT (#7781)
- The `$SYS.REQ.USER.INFO` response now includes the friendly nametag of the account and/or user if known (#7973)

JetStream

- The stream peer-remove command now accepts a peer ID as well as a server name (#7952)

MQTT

- Protocol compliance has been improved, including more error handling on invalid or malformed MQTT packets (#7933)

### Fixed

General

- Client connections are no longer registered after an auth callout timeout (#7932)
- Improved handling of duplicate headers
- A correctness bug when validating relative distinguished names has been fixed
- Secrets are now redacted correctly in trace logging (#7942)
- The expvar endpoint on the monitoring port now correctly redacts secrets from the command line arguments
- Trace headers are no longer incorrectly parsed when hitting max payload (#7954)
- When running as a Windows service, switching to lame duck mode should now correctly exit the process (#7958)
- The configuration digest no longer removes from the used variable tracking, which could cause configuration fields to disappear from the returned config (#7959)
- A bug which could result in the service import cycle detection failing to detect a genuine cycle has been fixed (#7961)
- The PROXY protocol v1 header parser no longer incorrectly discards some early protocol bytes from the client (#7962)
- The `Nats-Trace-Dest` message header for message tracing now requires that the client have publish permissions to the specified subject, an error is returned otherwise
- The route pool is now correctly populated if receiving a pong before handling the new route setup (#7971)

Leafnodes

- A panic when receiving a loop detection error before a connect message has been fixed
- Messages from leafnodes to non-shared service imports now correctly rebuild the request info header
- Leafnodes will now back off on receiving a minimum version required error, no longer requiring blocking the readloop (#7970)

JetStream

- Stream updates on clustered setups with async snapshots enabled should no longer result in the loss of consumer assignments, fixing the regression introduced in 2.12.5 (#7939)
- Fixed idempotent stream create with sources (#7928)
- Fixed a bug where mirror goroutines could get stuck stalling the mirror indefinitely (#7929)
- A panic that could occur when attempting to scale down a stream with an in-flight stream create and consumer create has been fixed (#7940)
- A panic when paginating on various JetStream API endpoints has been fixed
- An interior path traversal bug that could occur when purging JetStream accounts has been fixed
- Meta snapshot apply errors are now surfaced correctly so that the cluster monitor does not advance the applied index (#7944)
- Fixed an issue where extremely large JetStream reservations could overflow and violate tier limits
- Stream restores now ensure that the stream name in the restore subject matches that of the restored snapshot archive
- Stream ingest now correctly strips a NATS status header if present, avoiding incorrect classification of sourced or mirrored messages as control traffic
- The Raft layer now resets the vote correctly when switching to candidate state (#7956)
- The orphan consumer check no longer unexpectedly deletes direct consumers, which could affect sourcing and mirroring (#7957)
- The Raft layer no longer commits entries from previous terms by only allowing entries from our current term up to the commit (#7955)
- Stream restores are now processed directly from the wire without intermediate staging on the filesystem, improving the enforcement of limits and reservations on disk
- Stream sourcing now works correctly when sourcing into a stream with the Discard New Per Subject discard policy (#7896)

MQTT

- A panic that could occur when processing invalid fixed32 or fixed64 fields has been fixed (#7941)
- Persisted MQTT sessions can no longer be restored by a non-matching client ID 
- Restrict the implicit permissions for MQTT clients to `$MQTT.sub.` and `$MQTT.deliver.pubrel.` prefixes
- MQTT password are no longer exposed in the JWT field of monitoring endpoints or advisory messages
- NATS special characters (`.`, `>`, `*`, spaces, tabs) are no longer permitted in MQTT client IDs
- MQTT session flapping detection now uses monotonic time, fixing cases where it could be sensitive to NTP adjustments or clock drifts

WebSockets

- WebSocket protocol parsing no longer relies on potentially unbounded in-memory allocations from compressed or uncompressed frames

### Complete Changes
 
https://github.com/nats-io/nats-server/compare/v2.12.5...v2.12.6