VYPR
High severity7.5CISA KEVNVD Advisory· Published Oct 10, 2023· Updated May 12, 2026

CVE-2023-44487

CVE-2023-44487

Description

The HTTP/2 protocol allows a denial of service (server resource consumption) because request cancellation can reset many streams quickly, as exploited in the wild in August through October 2023.

Affected products

1
  • HTTP/2/HTTP/2description

Patches

3
f61d41a502bd

ver bump up

https://github.com/kazu-yamamoto/http2Kazu YamamotoOct 11, 2023via ghsa
2 files changed · +6 1
  • ChangeLog.md+5 0 modified
    @@ -1,3 +1,8 @@
    +## 4.2.1
    +
    +* Adding rate limit for RST_STREAM to work around CVE-2023-44487.
    +  [#94](https://github.com/kazu-yamamoto/http2/pull/94)
    +
     ## 4.2.0
     
     * Treating HALF_CLOSED_LOCAL correctly.
    
  • http2.cabal+1 1 modified
    @@ -1,6 +1,6 @@
     cabal-version:      >=1.10
     name:               http2
    -version:            4.2.0
    +version:            4.2.1
     license:            BSD3
     license-file:       LICENSE
     maintainer:         Kazu Yamamoto <kazu@iij.ad.jp>
    
58f75f665aa8

Merge pull request from GHSA-xpw8-rcwv-8f8p

https://github.com/netty/nettyNorman MaurerOct 10, 2023via ghsa
9 files changed · +316 41
  • codec-http2/src/main/java/io/netty/handler/codec/http2/AbstractHttp2ConnectionHandlerBuilder.java+22 2 modified
    @@ -109,6 +109,8 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
         private boolean autoAckPingFrame = true;
         private int maxQueuedControlFrames = Http2CodecUtil.DEFAULT_MAX_QUEUED_CONTROL_FRAMES;
         private int maxConsecutiveEmptyFrames = 2;
    +    private int maxRstFramesPerWindow = 200;
    +    private int secondsPerWindow = 30;
     
         /**
          * Sets the {@link Http2Settings} to use for the initial connection settings exchange.
    @@ -410,7 +412,7 @@ protected Http2PromisedRequestVerifier promisedRequestVerifier() {
     
         /**
          * Returns the maximum number of consecutive empty DATA frames (without end_of_stream flag) that are allowed before
    -     * the connection is closed. This allows to protected against the remote peer flooding us with such frames and
    +     * the connection is closed. This allows to protect against the remote peer flooding us with such frames and
          * so use up a lot of CPU. There is no valid use-case for empty DATA frames without end_of_stream flag.
          *
          * {@code 0} means no protection is in place.
    @@ -421,7 +423,7 @@ protected int decoderEnforceMaxConsecutiveEmptyDataFrames() {
     
         /**
          * Sets the maximum number of consecutive empty DATA frames (without end_of_stream flag) that are allowed before
    -     * the connection is closed. This allows to protected against the remote peer flooding us with such frames and
    +     * the connection is closed. This allows to protect against the remote peer flooding us with such frames and
          * so use up a lot of CPU. There is no valid use-case for empty DATA frames without end_of_stream flag.
          *
          * {@code 0} means no protection should be applied.
    @@ -433,6 +435,21 @@ protected B decoderEnforceMaxConsecutiveEmptyDataFrames(int maxConsecutiveEmptyF
             return self();
         }
     
    +    /**
    +     * Sets the maximum number RST frames that are allowed per window before
    +     * the connection is closed. This allows to protect against the remote peer flooding us with such frames and
    +     * so use up a lot of CPU.
    +     *
    +     * {@code 0} for any of the parameters means no protection should be applied.
    +     */
    +    protected B decoderEnforceMaxRstFramesPerWindow(int maxRstFramesPerWindow, int secondsPerWindow) {
    +        enforceNonCodecConstraints("decoderEnforceMaxRstFramesPerWindow");
    +        this.maxRstFramesPerWindow = checkPositiveOrZero(
    +                maxRstFramesPerWindow, "maxRstFramesPerWindow");
    +        this.secondsPerWindow = checkPositiveOrZero(secondsPerWindow, "secondsPerWindow");
    +        return self();
    +    }
    +
         /**
          * Determine if settings frame should automatically be acknowledged and applied.
          * @return this.
    @@ -575,6 +592,9 @@ private T buildFromCodec(Http2ConnectionDecoder decoder, Http2ConnectionEncoder
             if (maxConsecutiveEmptyDataFrames > 0) {
                 decoder = new Http2EmptyDataFrameConnectionDecoder(decoder, maxConsecutiveEmptyDataFrames);
             }
    +        if (maxRstFramesPerWindow > 0 && secondsPerWindow > 0) {
    +            decoder = new Http2MaxRstFrameDecoder(decoder, maxRstFramesPerWindow, secondsPerWindow);
    +        }
             final T handler;
             try {
                 // Call the abstract build method
    
  • codec-http2/src/main/java/io/netty/handler/codec/http2/Http2FrameCodecBuilder.java+6 0 modified
    @@ -194,6 +194,12 @@ public Http2FrameCodecBuilder decoderEnforceMaxConsecutiveEmptyDataFrames(int ma
             return super.decoderEnforceMaxConsecutiveEmptyDataFrames(maxConsecutiveEmptyFrames);
         }
     
    +    @Override
    +    public Http2FrameCodecBuilder decoderEnforceMaxRstFramesPerWindow(
    +            int maxConsecutiveEmptyFrames, int secondsPerWindow) {
    +        return super.decoderEnforceMaxRstFramesPerWindow(maxConsecutiveEmptyFrames, secondsPerWindow);
    +    }
    +
         /**
          * Build a {@link Http2FrameCodec} object.
          */
    
  • codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MaxRstFrameDecoder.java+58 0 added
    @@ -0,0 +1,58 @@
    +/*
    + * Copyright 2023 The Netty Project
    + *
    + * The Netty Project licenses this file to you under the Apache License,
    + * version 2.0 (the "License"); you may not use this file except in compliance
    + * with the License. You may obtain a copy of the License at:
    + *
    + *   https://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    + * License for the specific language governing permissions and limitations
    + * under the License.
    + */
    +package io.netty.handler.codec.http2;
    +
    +import static io.netty.util.internal.ObjectUtil.checkPositive;
    +
    +
    +/**
    + * Enforce a limit on the maximum number of RST frames that are allowed per a window
    + * before the connection will be closed with a GO_AWAY frame.
    + */
    +final class Http2MaxRstFrameDecoder extends DecoratingHttp2ConnectionDecoder {
    +    private final int maxRstFramesPerWindow;
    +    private final int secondsPerWindow;
    +
    +    Http2MaxRstFrameDecoder(Http2ConnectionDecoder delegate, int maxRstFramesPerWindow, int secondsPerWindow) {
    +        super(delegate);
    +        this.maxRstFramesPerWindow = checkPositive(maxRstFramesPerWindow, "maxRstFramesPerWindow");
    +        this.secondsPerWindow = checkPositive(secondsPerWindow, "secondsPerWindow");
    +    }
    +
    +    @Override
    +    public void frameListener(Http2FrameListener listener) {
    +        if (listener != null) {
    +            super.frameListener(new Http2MaxRstFrameListener(listener, maxRstFramesPerWindow, secondsPerWindow));
    +        } else {
    +            super.frameListener(null);
    +        }
    +    }
    +
    +    @Override
    +    public Http2FrameListener frameListener() {
    +        Http2FrameListener frameListener = frameListener0();
    +        // Unwrap the original Http2FrameListener as we add this decoder under the hood.
    +        if (frameListener instanceof Http2MaxRstFrameListener) {
    +            return ((Http2MaxRstFrameListener) frameListener).listener;
    +        }
    +        return frameListener;
    +    }
    +
    +    // Package-private for testing
    +    Http2FrameListener frameListener0() {
    +        return super.frameListener();
    +    }
    +}
    
  • codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MaxRstFrameListener.java+58 0 added
    @@ -0,0 +1,58 @@
    +/*
    + * Copyright 2023 The Netty Project
    + *
    + * The Netty Project licenses this file to you under the Apache License,
    + * version 2.0 (the "License"); you may not use this file except in compliance
    + * with the License. You may obtain a copy of the License at:
    + *
    + *   https://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    + * License for the specific language governing permissions and limitations
    + * under the License.
    + */
    +package io.netty.handler.codec.http2;
    +
    +import io.netty.channel.ChannelHandlerContext;
    +import io.netty.util.internal.logging.InternalLogger;
    +import io.netty.util.internal.logging.InternalLoggerFactory;
    +
    +import java.util.concurrent.TimeUnit;
    +
    +
    +final class Http2MaxRstFrameListener extends Http2FrameListenerDecorator {
    +    private static final InternalLogger logger = InternalLoggerFactory.getInstance(Http2MaxRstFrameListener.class);
    +
    +    private final long nanosPerWindow;
    +    private final int maxRstFramesPerWindow;
    +    private long lastRstFrameNano = System.nanoTime();
    +    private int receivedRstInWindow;
    +
    +    Http2MaxRstFrameListener(Http2FrameListener listener, int maxRstFramesPerWindow, int secondsPerWindow) {
    +        super(listener);
    +        this.maxRstFramesPerWindow = maxRstFramesPerWindow;
    +        this.nanosPerWindow = TimeUnit.SECONDS.toNanos(secondsPerWindow);
    +    }
    +
    +    @Override
    +    public void onRstStreamRead(ChannelHandlerContext ctx, int streamId, long errorCode) throws Http2Exception {
    +        long currentNano = System.nanoTime();
    +        if (currentNano - lastRstFrameNano >= nanosPerWindow) {
    +            lastRstFrameNano = currentNano;
    +            receivedRstInWindow = 1;
    +        } else {
    +            receivedRstInWindow++;
    +            if (receivedRstInWindow > maxRstFramesPerWindow) {
    +                Http2Exception exception = Http2Exception.connectionError(Http2Error.ENHANCE_YOUR_CALM,
    +                        "Maximum number of RST frames reached");
    +                logger.debug("{} Maximum number {} of RST frames reached within {} seconds, " +
    +                                "closing connection with {} error", ctx.channel(), maxRstFramesPerWindow,
    +                        TimeUnit.NANOSECONDS.toSeconds(nanosPerWindow), exception.error(), exception);
    +                throw exception;
    +            }
    +        }
    +        super.onRstStreamRead(ctx, streamId, errorCode);
    +    }
    +}
    
  • codec-http2/src/main/java/io/netty/handler/codec/http2/Http2MultiplexCodecBuilder.java+6 0 modified
    @@ -211,6 +211,12 @@ public Http2MultiplexCodecBuilder decoderEnforceMaxConsecutiveEmptyDataFrames(in
             return super.decoderEnforceMaxConsecutiveEmptyDataFrames(maxConsecutiveEmptyFrames);
         }
     
    +    @Override
    +    public Http2MultiplexCodecBuilder decoderEnforceMaxRstFramesPerWindow(
    +            int maxConsecutiveEmptyFrames, int secondsPerWindow) {
    +        return super.decoderEnforceMaxRstFramesPerWindow(maxConsecutiveEmptyFrames, secondsPerWindow);
    +    }
    +
         @Override
         public Http2MultiplexCodec build() {
             Http2FrameWriter frameWriter = this.frameWriter;
    
  • codec-http2/src/test/java/io/netty/handler/codec/http2/AbstractDecoratingHttp2ConnectionDecoderTest.java+63 0 added
    @@ -0,0 +1,63 @@
    +/*
    + * Copyright 2023 The Netty Project
    + *
    + * The Netty Project licenses this file to you under the Apache License, version 2.0 (the
    + * "License"); you may not use this file except in compliance with the License. You may obtain a
    + * copy of the License at:
    + *
    + * https://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software distributed under the License
    + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
    + * or implied. See the License for the specific language governing permissions and limitations under
    + * the License.
    + */
    +package io.netty.handler.codec.http2;
    +
    +import org.hamcrest.CoreMatchers;
    +import org.junit.jupiter.api.Test;
    +import org.mockito.ArgumentCaptor;
    +import org.mockito.invocation.InvocationOnMock;
    +import org.mockito.stubbing.Answer;
    +
    +import static org.junit.jupiter.api.Assertions.assertNull;
    +import static org.hamcrest.MatcherAssert.assertThat;
    +import static org.mockito.Mockito.mock;
    +import static org.mockito.Mockito.verify;
    +import static org.mockito.Mockito.when;
    +
    +public abstract class AbstractDecoratingHttp2ConnectionDecoderTest {
    +
    +    protected abstract DecoratingHttp2ConnectionDecoder newDecoder(Http2ConnectionDecoder decoder);
    +
    +    protected abstract Class<? extends Http2FrameListener> delegatingFrameListenerType();
    +
    +    @Test
    +    public void testDecoration() {
    +        Http2ConnectionDecoder delegate = mock(Http2ConnectionDecoder.class);
    +        final ArgumentCaptor<Http2FrameListener> listenerArgumentCaptor =
    +                ArgumentCaptor.forClass(Http2FrameListener.class);
    +        when(delegate.frameListener()).then(new Answer<Http2FrameListener>() {
    +            @Override
    +            public Http2FrameListener answer(InvocationOnMock invocationOnMock) {
    +                return listenerArgumentCaptor.getValue();
    +            }
    +        });
    +        Http2FrameListener listener = mock(Http2FrameListener.class);
    +        DecoratingHttp2ConnectionDecoder decoder = newDecoder(delegate);
    +        decoder.frameListener(listener);
    +        verify(delegate).frameListener(listenerArgumentCaptor.capture());
    +
    +        assertThat(decoder.frameListener(),
    +                CoreMatchers.not(CoreMatchers.instanceOf(delegatingFrameListenerType())));
    +    }
    +
    +    @Test
    +    public void testDecorationWithNull() {
    +        Http2ConnectionDecoder delegate = mock(Http2ConnectionDecoder.class);
    +
    +        DecoratingHttp2ConnectionDecoder decoder = newDecoder(delegate);
    +        decoder.frameListener(null);
    +        assertNull(decoder.frameListener());
    +    }
    +}
    
  • codec-http2/src/test/java/io/netty/handler/codec/http2/Http2EmptyDataFrameConnectionDecoderTest.java+7 39 modified
    @@ -14,47 +14,15 @@
      */
     package io.netty.handler.codec.http2;
     
    -import org.hamcrest.CoreMatchers;
    -import org.junit.jupiter.api.Test;
    -import org.mockito.ArgumentCaptor;
    -import org.mockito.invocation.InvocationOnMock;
    -import org.mockito.stubbing.Answer;
    +public class Http2EmptyDataFrameConnectionDecoderTest extends AbstractDecoratingHttp2ConnectionDecoderTest {
     
    -import static org.hamcrest.MatcherAssert.assertThat;
    -import static org.junit.jupiter.api.Assertions.assertNull;
    -import static org.mockito.Mockito.mock;
    -import static org.mockito.Mockito.verify;
    -import static org.mockito.Mockito.when;
    -
    -public class Http2EmptyDataFrameConnectionDecoderTest {
    -
    -    @Test
    -    public void testDecoration() {
    -        Http2ConnectionDecoder delegate = mock(Http2ConnectionDecoder.class);
    -        final ArgumentCaptor<Http2FrameListener> listenerArgumentCaptor =
    -                ArgumentCaptor.forClass(Http2FrameListener.class);
    -        when(delegate.frameListener()).then(new Answer<Http2FrameListener>() {
    -            @Override
    -            public Http2FrameListener answer(InvocationOnMock invocationOnMock) {
    -                return listenerArgumentCaptor.getValue();
    -            }
    -        });
    -        Http2FrameListener listener = mock(Http2FrameListener.class);
    -        Http2EmptyDataFrameConnectionDecoder decoder = new Http2EmptyDataFrameConnectionDecoder(delegate, 2);
    -        decoder.frameListener(listener);
    -        verify(delegate).frameListener(listenerArgumentCaptor.capture());
    -
    -        assertThat(decoder.frameListener(),
    -                CoreMatchers.not(CoreMatchers.instanceOf(Http2EmptyDataFrameListener.class)));
    -        assertThat(decoder.frameListener0(), CoreMatchers.instanceOf(Http2EmptyDataFrameListener.class));
    +    @Override
    +    protected DecoratingHttp2ConnectionDecoder newDecoder(Http2ConnectionDecoder decoder) {
    +        return new Http2EmptyDataFrameConnectionDecoder(decoder, 2);
         }
     
    -    @Test
    -    public void testDecorationWithNull() {
    -        Http2ConnectionDecoder delegate = mock(Http2ConnectionDecoder.class);
    -
    -        Http2EmptyDataFrameConnectionDecoder decoder = new Http2EmptyDataFrameConnectionDecoder(delegate, 2);
    -        decoder.frameListener(null);
    -        assertNull(decoder.frameListener());
    +    @Override
    +    protected Class<? extends Http2FrameListener> delegatingFrameListenerType() {
    +        return Http2EmptyDataFrameListener.class;
         }
     }
    
  • codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MaxRstFrameConnectionDecoderTest.java+28 0 added
    @@ -0,0 +1,28 @@
    +/*
    + * Copyright 2023 The Netty Project
    + *
    + * The Netty Project licenses this file to you under the Apache License, version 2.0 (the
    + * "License"); you may not use this file except in compliance with the License. You may obtain a
    + * copy of the License at:
    + *
    + * https://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software distributed under the License
    + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
    + * or implied. See the License for the specific language governing permissions and limitations under
    + * the License.
    + */
    +package io.netty.handler.codec.http2;
    +
    +public class Http2MaxRstFrameConnectionDecoderTest extends AbstractDecoratingHttp2ConnectionDecoderTest {
    +
    +    @Override
    +    protected DecoratingHttp2ConnectionDecoder newDecoder(Http2ConnectionDecoder decoder) {
    +        return new Http2MaxRstFrameDecoder(decoder, 200, 30);
    +    }
    +
    +    @Override
    +    protected Class<? extends Http2FrameListener> delegatingFrameListenerType() {
    +        return Http2MaxRstFrameListener.class;
    +    }
    +}
    
  • codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MaxRstFrameListenerTest.java+68 0 added
    @@ -0,0 +1,68 @@
    +/*
    + * Copyright 2023 The Netty Project
    + *
    + * The Netty Project licenses this file to you under the Apache License, version 2.0 (the
    + * "License"); you may not use this file except in compliance with the License. You may obtain a
    + * copy of the License at:
    + *
    + * https://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software distributed under the License
    + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
    + * or implied. See the License for the specific language governing permissions and limitations under
    + * the License.
    + */
    +package io.netty.handler.codec.http2;
    +
    +import io.netty.channel.ChannelHandlerContext;
    +import org.junit.jupiter.api.BeforeEach;
    +import org.junit.jupiter.api.Test;
    +import org.junit.jupiter.api.function.Executable;
    +import org.mockito.Mock;
    +
    +import static org.junit.jupiter.api.Assertions.assertEquals;
    +import static org.junit.jupiter.api.Assertions.assertThrows;
    +import static org.mockito.ArgumentMatchers.anyInt;
    +import static org.mockito.Mockito.eq;
    +import static org.mockito.Mockito.times;
    +import static org.mockito.Mockito.verify;
    +import static org.mockito.MockitoAnnotations.initMocks;
    +
    +public class Http2MaxRstFrameListenerTest {
    +
    +    @Mock
    +    private Http2FrameListener frameListener;
    +    @Mock
    +    private ChannelHandlerContext ctx;
    +
    +    private Http2MaxRstFrameListener listener;
    +
    +    @BeforeEach
    +    public void setUp() {
    +        initMocks(this);
    +    }
    +
    +    @Test
    +    public void testMaxRstFramesReached() throws Http2Exception {
    +        listener = new Http2MaxRstFrameListener(frameListener, 1, 10);
    +        listener.onRstStreamRead(ctx, 1, Http2Error.STREAM_CLOSED.code());
    +
    +        Http2Exception ex = assertThrows(Http2Exception.class, new Executable() {
    +            @Override
    +            public void execute() throws Throwable {
    +                listener.onRstStreamRead(ctx, 2, Http2Error.STREAM_CLOSED.code());
    +            }
    +        });
    +        assertEquals(Http2Error.ENHANCE_YOUR_CALM, ex.error());
    +        verify(frameListener, times(1)).onRstStreamRead(eq(ctx), anyInt(), eq(Http2Error.STREAM_CLOSED.code()));
    +    }
    +
    +    @Test
    +    public void testRstFrames() throws Exception {
    +        listener = new Http2MaxRstFrameListener(frameListener, 1, 1);
    +        listener.onRstStreamRead(ctx, 1, Http2Error.STREAM_CLOSED.code());
    +        Thread.sleep(1100);
    +        listener.onRstStreamRead(ctx, 1, Http2Error.STREAM_CLOSED.code());
    +        verify(frameListener, times(2)).onRstStreamRead(eq(ctx), anyInt(), eq(Http2Error.STREAM_CLOSED.code()));
    +    }
    +}
    
944332bb15bd

Improvements to HTTP/2 overhead protection.

https://github.com/apache/tomcatMark ThomasOct 5, 2023via ghsa
4 files changed · +31 2
  • java/org/apache/coyote/http2/Http2Protocol.java+18 1 modified
    @@ -63,8 +63,10 @@ public class Http2Protocol implements UpgradeProtocol {
         // Maximum amount of streams which can be concurrently executed over
         // a single connection
         static final int DEFAULT_MAX_CONCURRENT_STREAM_EXECUTION = 20;
    -
    +    // Default factor used when adjusting overhead count for overhead frames
         static final int DEFAULT_OVERHEAD_COUNT_FACTOR = 10;
    +    // Default factor used when adjusting overhead count for reset frames
    +    static final int DEFAULT_OVERHEAD_RESET_FACTOR = 50;
         // Not currently configurable. This makes the practical limit for
         // overheadCountFactor to be ~20. The exact limit will vary with traffic
         // patterns.
    @@ -98,6 +100,7 @@ public class Http2Protocol implements UpgradeProtocol {
         private int maxTrailerCount = Constants.DEFAULT_MAX_TRAILER_COUNT;
         private int maxTrailerSize = Constants.DEFAULT_MAX_TRAILER_SIZE;
         private int overheadCountFactor = DEFAULT_OVERHEAD_COUNT_FACTOR;
    +    private int overheadResetFactor = DEFAULT_OVERHEAD_RESET_FACTOR;
         private int overheadContinuationThreshold = DEFAULT_OVERHEAD_CONTINUATION_THRESHOLD;
         private int overheadDataThreshold = DEFAULT_OVERHEAD_DATA_THRESHOLD;
         private int overheadWindowUpdateThreshold = DEFAULT_OVERHEAD_WINDOW_UPDATE_THRESHOLD;
    @@ -339,6 +342,20 @@ public void setOverheadCountFactor(int overheadCountFactor) {
         }
     
     
    +    public int getOverheadResetFactor() {
    +        return overheadResetFactor;
    +    }
    +
    +
    +    public void setOverheadResetFactor(int overheadResetFactor) {
    +        if (overheadResetFactor < 0) {
    +            this.overheadResetFactor = 0;
    +        } else {
    +            this.overheadResetFactor = overheadResetFactor;
    +        }
    +    }
    +
    +
         public int getOverheadContinuationThreshold() {
             return overheadContinuationThreshold;
         }
    
  • java/org/apache/coyote/http2/Http2UpgradeHandler.java+2 0 modified
    @@ -1812,6 +1812,7 @@ public void reset(int streamId, long errorCode) throws Http2Exception {
                 log.debug(sm.getString("upgradeHandler.reset.receive", getConnectionId(), Integer.toString(streamId),
                         Long.toString(errorCode)));
             }
    +        increaseOverheadCount(FrameType.RST, getProtocol().getOverheadResetFactor());
             AbstractNonZeroStream abstractNonZeroStream = getAbstractNonZeroStream(streamId, true);
             abstractNonZeroStream.checkState(FrameType.RST);
             if (abstractNonZeroStream instanceof Stream) {
    @@ -1945,6 +1946,7 @@ public void incrementWindowSize(int streamId, int increment) throws Http2Excepti
     
         @Override
         public void priorityUpdate(int prioritizedStreamID, Priority p) throws Http2Exception {
    +        increaseOverheadCount(FrameType.PRIORITY_UPDATE);
             AbstractNonZeroStream abstractNonZeroStream = getAbstractNonZeroStream(prioritizedStreamID, true);
             if (abstractNonZeroStream instanceof Stream) {
                 Stream stream = (Stream) abstractNonZeroStream;
    
  • webapps/docs/changelog.xml+3 0 modified
    @@ -163,6 +163,9 @@
           <fix>
             Align validation of HTTP trailer fields with standard fields. (markt)
           </fix>
    +      <fix>
    +        Improvements to HTTP/2 overhead protection. (markt)
    +      </fix>
         </changelog>
       </subsection>
       <subsection name="Jasper">
    
  • webapps/docs/config/http2.xml+8 1 modified
    @@ -222,14 +222,21 @@
           count starts at <code>-10 * overheadCountFactor</code>. The count is
           decreased by 20 for each data frame sent or received and each headers frame
           received. The count is increased by the <code>overheadCountFactor</code>
    -      for each setting received, priority frame received and ping received. If
    +      for each setting, priority, priority update and ping frame received. If
           the overhead count exceeds zero, the connection is closed. A value of less
           than <code>1</code> disables this protection. In normal usage a value of
           approximately <code>20</code> or higher will close the connection before
           any streams can complete. If not specified, a default value of
           <code>10</code> will be used.</p>
         </attribute>
     
    +    <attribute name="overheadResetFactor" required="false">
    +      <p>The amount by which the overhead count (see
    +      <strong>overheadCountFactor</strong>) will be increased for each reset
    +      frame received. If not specified, a default value of <code>50</code> will
    +      be used. A value of less than zero will be treated as zero.</p>
    +    </attribute>
    +
         <attribute name="overheadDataThreshold" required="false">
           <p>The threshold below which the average payload size of the current and
           previous non-final <code>DATA</code> frames will trigger an increase in
    

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

246

News mentions

0

No linked articles in our index yet.