Skip to content

Conversation

@renovate
Copy link
Contributor

@renovate renovate bot commented Oct 10, 2025

This PR contains the following updates:

Package Change Age Confidence
github.com/quic-go/quic-go v0.48.2 -> v0.49.1 age confidence

GitHub Vulnerability Alerts

CVE-2025-59530

Summary

A misbehaving or malicious server can trigger an assertion in a quic-go client (and crash the process) by sending a premature HANDSHAKE_DONE frame during the handshake.

Impact

A misbehaving or malicious server can cause a denial-of-service (DoS) attack on the quic-go client by triggering an assertion failure, leading to a process crash. This requires no authentication and can be exploited during the handshake phase. Observed in the wild with certain server implementations (e.g. Solana's Firedancer QUIC).

Affected Versions

  • All versions prior to v0.49.1 (for the 0.49 branch)
  • Versions v0.50.0 to v0.54.0 (inclusive)
  • Fixed in v0.49.1, v0.54.1, and v0.55.0 onward

Users are recommended to upgrade to the latest patched version in their respective maintenance branch or to v0.55.0 or later.

Details

For a regular 1-RTT handshake, QUIC uses three sets of keys to encrypt / decrypt QUIC packets:

  • Initial keys (derived from a static key and the connection ID)
  • Handshake keys (derived from the client's and server's key shares in the TLS handshake)
  • 1-RTT keys (derived when the TLS handshake finishes)

On the client side, Initial keys are discarded when the first Handshake packet is sent. Handshake keys are discarded when the server's HANDSHAKE_DONE frame is received, as specified in section 4.9.2 of RFC 9001. Crucially, Initial keys are always dropped before Handshake keys in a standard handshake.

Due to packet reordering, it is possible to receive a packet with a higher encryption level before the key for that encryption level has been derived. For example, the server's Handshake packets (containing, among others, the TLS certificate) might arrive before the server's Initial packet (which contains the TLS ServerHello). In that case, the client queues the Handshake packets and decrypts them as soon as it has processed the ServerHello and derived Handshake keys.

After completion of the handshake, Initial and Handshake packets are not needed anymore and will be dropped. quic-go implements an assertion that no packets are queued after completion of the handshake.

A misbehaving or malicious server can trigger this assertion, and thereby cause a panic, by sending a HANDSHAKE_DONE frame before actually completing the handshake. In that case, Handshake keys would be dropped before Initial keys.

This can only happen if the server implementation is misbehaving: the server can only complete the handshake after receiving the client's TLS Finished message (which is sent in Handshake packets).

The Fix

quic-go needs to be able to handle misbehaving server implementations, including those that prematurely send a HANDSHAKE_DONE frame. We now discard Initial keys when receiving a HANDSHAKE_DONE frame, thereby correctly handling premature HANDSHAKE_DONE frames. The fix was implemented in https://github.com/quic-go/quic-go/pull/5354.


quic-go: Panic occurs when queuing undecryptable packets after handshake completion

CVE-2025-59530 / GHSA-47m2-4cr7-mhcw

More information

Details

Summary

A misbehaving or malicious server can trigger an assertion in a quic-go client (and crash the process) by sending a premature HANDSHAKE_DONE frame during the handshake.

Impact

A misbehaving or malicious server can cause a denial-of-service (DoS) attack on the quic-go client by triggering an assertion failure, leading to a process crash. This requires no authentication and can be exploited during the handshake phase. Observed in the wild with certain server implementations (e.g. Solana's Firedancer QUIC).

Affected Versions
  • All versions prior to v0.49.1 (for the 0.49 branch)
  • Versions v0.50.0 to v0.54.0 (inclusive)
  • Fixed in v0.49.1, v0.54.1, and v0.55.0 onward

Users are recommended to upgrade to the latest patched version in their respective maintenance branch or to v0.55.0 or later.

Details

For a regular 1-RTT handshake, QUIC uses three sets of keys to encrypt / decrypt QUIC packets:

  • Initial keys (derived from a static key and the connection ID)
  • Handshake keys (derived from the client's and server's key shares in the TLS handshake)
  • 1-RTT keys (derived when the TLS handshake finishes)

On the client side, Initial keys are discarded when the first Handshake packet is sent. Handshake keys are discarded when the server's HANDSHAKE_DONE frame is received, as specified in section 4.9.2 of RFC 9001. Crucially, Initial keys are always dropped before Handshake keys in a standard handshake.

Due to packet reordering, it is possible to receive a packet with a higher encryption level before the key for that encryption level has been derived. For example, the server's Handshake packets (containing, among others, the TLS certificate) might arrive before the server's Initial packet (which contains the TLS ServerHello). In that case, the client queues the Handshake packets and decrypts them as soon as it has processed the ServerHello and derived Handshake keys.

After completion of the handshake, Initial and Handshake packets are not needed anymore and will be dropped. quic-go implements an assertion that no packets are queued after completion of the handshake.

A misbehaving or malicious server can trigger this assertion, and thereby cause a panic, by sending a HANDSHAKE_DONE frame before actually completing the handshake. In that case, Handshake keys would be dropped before Initial keys.

This can only happen if the server implementation is misbehaving: the server can only complete the handshake after receiving the client's TLS Finished message (which is sent in Handshake packets).

The Fix

quic-go needs to be able to handle misbehaving server implementations, including those that prematurely send a HANDSHAKE_DONE frame. We now discard Initial keys when receiving a HANDSHAKE_DONE frame, thereby correctly handling premature HANDSHAKE_DONE frames. The fix was implemented in https://github.com/quic-go/quic-go/pull/5354.

Severity

  • CVSS Score: 7.5 / 10 (High)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Release Notes

quic-go/quic-go (github.com/quic-go/quic-go)

v0.49.1

Compare Source

v0.49.0

Compare Source

In this release, we added support for HTTP client traces. We also fixed a large number of bugs that could lead to connection stalls, deadlocks and memory leaks. See the "Major Fixes" section for more details.

New Features

  • http3: add support for client traces net/http/httptrace.ClientTrace: #​4749. Thanks to @​lRoccoon for the contribution!

Major Fixes

  • fix accounting for lost RESET_STREAM frames in the stream, leading to potential connection stalls / deadlocks: #​4804. Thanks to @​Wondertan for reporting and testing the fix!
  • fix memory leak when the connection ID is rotated when the CONNECTION_CLOSE packet is sent: #​4852. Thanks to @​MarcoPolo for debugging this issue and contributing a fix!
  • http3: fix QUIC connection re-dialing logic: #​4854, #​4875, #​4879
  • trigger sending of a new packet when a MAX_DATA frame (connection-level flow control update) is queued: #​4844
  • Transport.Close was reworked: calls to Transport.Dial are now canceled, and return the newly introduced ErrTransportClosed, as do calls to Transport.Listen: #​4883

Enhancements

  • trace dropping of packets by the Transport when no server is set: #​4789
  • trace dropping of packets that the Transport doesn't send a stateless for: #​4826
  • drain received packets when the connection is closed: #​4773
  • add Prometheus metrics for sent and received packets: #​4910
  • reduce calls to time.Now all over the code base: #​4731, #​4885, #​4886, #​4906
  • packetize DATA_BLOCKED frames in the same QUIC packet that caused us to block on connection-level flow control: #​4845
  • packetize STREAM_DATA_BLOCKED frames in the same QUIC packed that caused us to block on stream-level flow control: #​4801
  • we now don't enforce that only one Transport listens on any given net.PacketConn: #​4851

Other Fixes

  • drain the server's connection accept queue before returning ErrClosed from Accept: #​4846. Thanks to @​sukunrt for discovering this bug and providing very helpful reviews!
  • preserve the error returned from SendStream.Write if it is closed after is canceled: #​4882
  • fix race condition on concurrent calls to Transport.Dial and Transport.Close: #​4904
  • qlog: fix logging of packet_in_flight on the metrics_updated event: #​4895
  • fix errors.Is error comparisons: #​4824, #​4825, #​4877
  • http3: fix race condition on concurrent calls to http.Response.Body.Close: #​4798. Thanks to @​RPRX for the contribution!
  • flowcontrol: reset the connection send window on 0-RTT rejection: #​4764
  • wait for connection to shut down when the Dial context is cancelled: #​4872
  • http3: the http.Request.Body is now properly closed on all code paths that return a non-nil error: #​4874
  • NEW_CONNECTION_ID frames are now rejected when zero-length connection IDs are used, as required by the RFC: #​4878
  • the stream ID of STREAM_DATA_BLOCKED frames is now validated, as required by the RFC: #​4836
  • fix ECN markings of packets sent in GSO batches when the marking changes: #​4835
  • the AEAD used to calculate the Retry Integrity Tag is now created lazily, avoiding a panic on initialization when using Go 1.24 FIPS-only mode: #​4916
  • use a 24h maximum token age as default value for Transport.MaxTokenAge: #​4763

Behind the Scenes

In the v0.48.0 release, we started migrating our test suite away from Ginkgo (tracking issue: #​3652). This is an absolutely massive endeavor. Before we started, the number of LOC of Ginkgo tests was more than 41,000.

In this release, we're bringing this number down to less than 8,500 LOC: #​4736, #​4746, #​4775, #​4783, #​4788, #​4790, #​4795, #​4796, #​4797, #​4799, #​4814, #​4816, #​4817, #​4823, #​4837, #​4842, #​4847, #​4848, #​4849, #​4853, #​4857, #​4860, #​4861, #​4862, #​4863, #​4864, #​4865, #​4869, #​4876, #​4881, #​4907.

There's still a lot of work ahead, but we'll hopefully be able to finish this item in the next couple of months.

Changelog

New Contributors

Full Changelog: quic-go/quic-go@v0.48.2...v0.49.0


Configuration

📅 Schedule: Branch creation - "" (UTC), Automerge - At any time (no schedule defined).

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate renovate bot added the automated label Oct 10, 2025
@renovate
Copy link
Contributor Author

renovate bot commented Oct 10, 2025

ℹ Artifact update notice

File name: go.mod

In order to perform the update(s) described in the table above, Renovate ran the go get command, which resulted in the following additional change(s):

  • 1 additional dependency was updated

Details:

Package Change
go.uber.org/mock v0.4.0 -> v0.5.0

@renovate renovate bot changed the title Update module github.com/quic-go/quic-go to v0.49.1 [SECURITY] Update module github.com/quic-go/quic-go to v0.49.1 [SECURITY] - autoclosed Oct 19, 2025
@renovate renovate bot closed this Oct 19, 2025
@renovate renovate bot deleted the renovate/go-github.com-quic-go-quic-go-vulnerability branch October 19, 2025 23:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant