VYPR
High severity7.5NVD Advisory· Published Apr 4, 2024· Updated Apr 15, 2026

CVE-2024-22189

CVE-2024-22189

Description

quic-go is an implementation of the QUIC protocol in Go. Prior to version 0.42.0, an attacker can cause its peer to run out of memory sending a large number of NEW_CONNECTION_ID frames that retire old connection IDs. The receiver is supposed to respond to each retirement frame with a RETIRE_CONNECTION_ID frame. The attacker can prevent the receiver from sending out (the vast majority of) these RETIRE_CONNECTION_ID frames by collapsing the peers congestion window (by selectively acknowledging received packets) and by manipulating the peer's RTT estimate. Version 0.42.0 contains a patch for the issue. No known workarounds are available.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/quic-go/quic-goGo
< 0.42.00.42.0

Patches

1
4a99b816ae3a

close connection when an abnormally large number of frames are queued (#4369)

https://github.com/quic-go/quic-goMarten SeemannMar 18, 2024via ghsa
3 files changed · +44 4
  • connection.go+3 0 modified
    @@ -521,6 +521,9 @@ func (s *connection) run() error {
     
     runLoop:
     	for {
    +		if s.framer.QueuedTooManyControlFrames() {
    +			s.closeLocal(&qerr.TransportError{ErrorCode: InternalError})
    +		}
     		// Close immediately if requested
     		select {
     		case closeErr = <-s.closeChan:
    
  • framer.go+24 4 modified
    @@ -21,9 +21,19 @@ type framer interface {
     	AppendStreamFrames([]ackhandler.StreamFrame, protocol.ByteCount, protocol.Version) ([]ackhandler.StreamFrame, protocol.ByteCount)
     
     	Handle0RTTRejection() error
    +
    +	// QueuedTooManyControlFrames says if the control frame queue exceeded its maximum queue length.
    +	// This is a hack.
    +	// It is easier to implement than propagating an error return value in QueueControlFrame.
    +	// The correct solution would be to queue frames with their respective structs.
    +	// See https://github.com/quic-go/quic-go/issues/4271 for the queueing of stream-related control frames.
    +	QueuedTooManyControlFrames() bool
     }
     
    -const maxPathResponses = 256
    +const (
    +	maxPathResponses = 256
    +	maxControlFrames = 16 << 10
    +)
     
     type framerI struct {
     	mutex sync.Mutex
    @@ -33,9 +43,10 @@ type framerI struct {
     	activeStreams map[protocol.StreamID]struct{}
     	streamQueue   ringbuffer.RingBuffer[protocol.StreamID]
     
    -	controlFrameMutex sync.Mutex
    -	controlFrames     []wire.Frame
    -	pathResponses     []*wire.PathResponseFrame
    +	controlFrameMutex          sync.Mutex
    +	controlFrames              []wire.Frame
    +	pathResponses              []*wire.PathResponseFrame
    +	queuedTooManyControlFrames bool
     }
     
     var _ framer = &framerI{}
    @@ -73,6 +84,11 @@ func (f *framerI) QueueControlFrame(frame wire.Frame) {
     		f.pathResponses = append(f.pathResponses, pr)
     		return
     	}
    +	// This is a hack.
    +	if len(f.controlFrames) >= maxControlFrames {
    +		f.queuedTooManyControlFrames = true
    +		return
    +	}
     	f.controlFrames = append(f.controlFrames, frame)
     }
     
    @@ -105,6 +121,10 @@ func (f *framerI) AppendControlFrames(frames []ackhandler.Frame, maxLen protocol
     	return frames, length
     }
     
    +func (f *framerI) QueuedTooManyControlFrames() bool {
    +	return f.queuedTooManyControlFrames
    +}
    +
     func (f *framerI) AddActiveStream(id protocol.StreamID) {
     	f.mutex.Lock()
     	if _, ok := f.activeStreams[id]; !ok {
    
  • framer_test.go+17 0 modified
    @@ -109,6 +109,23 @@ var _ = Describe("Framer", func() {
     			Expect(fs).To(HaveLen(2))
     			Expect(length).To(Equal(ping.Length(version) + ncid.Length(version)))
     		})
    +
    +		It("detects when too many frames are queued", func() {
    +			for i := 0; i < maxControlFrames-1; i++ {
    +				framer.QueueControlFrame(&wire.PingFrame{})
    +				framer.QueueControlFrame(&wire.PingFrame{})
    +				Expect(framer.QueuedTooManyControlFrames()).To(BeFalse())
    +				frames, _ := framer.AppendControlFrames([]ackhandler.Frame{}, 1, protocol.Version1)
    +				Expect(frames).To(HaveLen(1))
    +				Expect(framer.(*framerI).controlFrames).To(HaveLen(i + 1))
    +			}
    +			framer.QueueControlFrame(&wire.PingFrame{})
    +			Expect(framer.QueuedTooManyControlFrames()).To(BeFalse())
    +			Expect(framer.(*framerI).controlFrames).To(HaveLen(maxControlFrames))
    +			framer.QueueControlFrame(&wire.PingFrame{})
    +			Expect(framer.QueuedTooManyControlFrames()).To(BeTrue())
    +			Expect(framer.(*framerI).controlFrames).To(HaveLen(maxControlFrames))
    +		})
     	})
     
     	Context("handling PATH_RESPONSE frames", func() {
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.