A remote, unauthenticated peer can leak one direct ByteBuf per HTTP/2 DATA frame in
applications that enable HTTP/2 content decompression via DelegatingDecompressorFrameListener.
When a DATA frame is processed for a stream whose decompressor has already been closed,
Http2Decompressor.decompress(...) retains the frame buffer but never releases it on the error
path, so its reference count never returns to zero. Repeating this over a long-lived HTTP/2
connection exhausts direct memory and crashes the JVM with OutOfMemoryError — a denial of service.
In codec-http2/src/main/java/io/netty/handler/codec/http2/DelegatingDecompressorFrameListener.java,
Http2Decompressor.decompress(...) does:
// around line 433
decompressor.writeInbound(data.retain());
The argument data.retain() is evaluated before writeInbound(...) executes, incrementing the
buffer's reference count (refCnt: 1 -> 2). The very first statement of
EmbeddedChannel.writeInbound(...) is ensureOpen() (EmbeddedChannel.java:360), which throws
ClosedChannelException when the decompressor's internal EmbeddedChannel has already been closed.
When that happens:
DATA payload has been retain()ed but never entered the pipeline, so the decoder's
finally { release() } never runs;catch (Throwable t) block in decompress(...) (around line 451) does not
release the extra reference;The decompressor channel is closed on a reachable path:
Http2Connection onStreamRemoved → Http2Decompressor.cleanup() →
EmbeddedChannel.finishAndReleaseAll()
(DelegatingDecompressorFrameListener.java:125-133 and 418-420).
A peer that sends DATA frames for a stream whose decompressor has already been cleaned up (e.g.
continuing to send DATA after END_STREAM / stream removal) thus leaks one direct ByteBuf per
frame....
4.1.136.Final4.2.16.FinalExploitability
AV:NAC:LPR:NUI:NScope
S:UImpact
C:NI:NA:H7.5/CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:HResource Management