high
CVE
CVE-2026-50010, CVE-2026-50011, CVE-2026-50020, CVE-2026-50560
CWE
CWE-347, CWE-444, CWE-400, CWE-770
Affected Surface
Maven consumers of `io.netty:netty-handler` on Netty 4.1.x before 4.1.135.Final or 4.2.x before 4.2.15.Final when client TLS contexts call `SslContextBuilder.forClient().trustManager(...)` with a plain `X509TrustManager`, Maven consumers of `io.netty:netty-codec-http` on Netty 4.1.x before 4.1.135.Final or 4.2.x before 4.2.15.Final parsing attacker-controlled HTTP/1.1 traffic, Maven consumers of `io.netty:netty-codec-http2` on Netty 4.1.x before 4.1.135.Final or 4.2.x before 4.2.15.Final acting as HTTP/2 servers, Maven consumers of `io.netty:netty-codec-redis` on Netty 4.1.x before 4.1.135.Final or 4.2.x before 4.2.15.Final decoding untrusted RESP traffic, Java services and frameworks that pull these Netty modules transitively through higher-level dependencies
Netty’s June 4.1.135.Final / 4.2.15.Final security release is the kind of Java infrastructure update that can look routine until you read the fix train closely. The issues that landed in NVD on 12 June 2026 are not obscure edge cases in unused extensions. They sit in the parts of Netty that terminate TLS, parse HTTP/1.1, implement HTTP/2, and aggregate RESP arrays.
That matters because many teams do not consume Netty directly. They inherit it transitively through higher-level frameworks, API gateways, RPC stacks, or custom protocol servers. If your AppSec process only watches the top-level framework release notes and not the underlying io.netty:* modules, this is the kind of security train that can slip through.
What is affected
The four highest-signal issues from the June NVD publication window map cleanly to four different Netty modules:
| CVE | Maven coordinate | Vulnerable behavior | Fixed in |
|---|---|---|---|
CVE-2026-50010 | io.netty:netty-handler | Custom client trust-manager path can silently disable hostname verification | 4.1.135.Final, 4.2.15.Final |
CVE-2026-50020 | io.netty:netty-codec-http | HTTP/1.1 parser accepts leading control bytes beyond CRLF and can create request-boundary disagreement | 4.1.135.Final, 4.2.15.Final |
CVE-2026-50011 | io.netty:netty-codec-redis | Redis array header can force attacker-sized pre-allocation before child messages exist | 4.1.135.Final, 4.2.15.Final |
CVE-2026-50560 | io.netty:netty-codec-http2 | Server can be pushed into response-write failure by honoring a hostile client’s advertised header-list limit | 4.1.135.Final, 4.2.15.Final |
The release notes show these four were only part of a broader security-heavy train. The same release also fixed adjacent Netty handler, Redis, DNS, HAProxy, and HTTP/2 issues such as CVE-2026-45416, CVE-2026-47244, CVE-2026-48043, CVE-2026-44250, CVE-2026-44890, and CVE-2026-48006. Even if one specific CVE does not apply to your deployment, teams should review the whole release rather than cherry-picking a single advisory.
CVE-2026-50010: a custom trust manager can turn off hostname verification
This is the issue most likely to surprise seasoned Java developers because it breaks a security assumption rather than a parser. NVD’s description is precise: a caller-supplied plain X509TrustManager was being wrapped into an X509ExtendedTrustManager, which accidentally prevented later wrappers from adding endpoint identification.
Before the fix, the relevant path in SimpleTrustManagerFactory effectively looked like this:
if (tm instanceof X509TrustManager && !(tm instanceof X509ExtendedTrustManager)) {
trustManagers[i] = new X509TrustManagerWrapper((X509TrustManager) tm);
}
The problem is not just the wrapper itself. Once the object already is an X509ExtendedTrustManager, neither the JDK’s internal trust-manager wrapper path nor Netty’s own OpenSSL wrapper has a reason to re-wrap it and enforce hostname checking. That means code shaped like this can lose the protection developers think they are getting:
SslContext sslContext = SslContextBuilder
.forClient()
.trustManager(somePlainX509TrustManager)
.build();
Netty 4.2 already defaults endpointIdentificationAlgorithm to "HTTPS", but CVE-2026-50010 shows that a well-intentioned custom trust-manager hook can still nullify the hostname-verification step.
The fix is instructive because it removes automatic wrapping from the generic trust-manager factory while keeping explicit insecure behavior isolated to the intentionally dangerous path:
// removed from SimpleTrustManagerFactory
// kept only where Netty intentionally disables verification
In other words, InsecureTrustManagerFactory stays insecure on purpose, but the ordinary SimpleTrustManagerFactory path stops silently suppressing hostname verification for callers who never asked for that.
CVE-2026-50020: Netty was more lenient than RFC 9112 permits
The HTTP/1.1 issue is a classic parser-disagreement problem. RFC 9112 permits servers to ignore empty leading CRLF lines before the request line as a narrow interoperability concession. Netty’s HttpObjectDecoder went beyond that and skipped any ISO control characters before the initial line.
The fix shows the parser state becoming more explicit:
private enum State {
SKIP_INITIAL_LINE_CHARS,
READ_INITIAL,
READ_HEADER,
...
}
And the actual byte scan now distinguishes “ignore ordinary control garbage” from “only tolerate CRLF when strict checks are enabled”:
final int firstNonLineIndex = buffer.forEachByte(
readerIndex,
maxToSkip,
strictCRLFCheck == null ? SKIP_CONTROL_CHARS_BYTES : ByteProcessor.FIND_NON_CRLF
);
There is also a new regression test that makes the security boundary very concrete:
buf.writeByte(0x00); // NUL
buf.writeByte(0x01); // SOH
buf.writeCharSequence("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n", US_ASCII);
That request is now rejected rather than silently normalized.
Why this matters to AppSec teams: request smuggling and request-boundary confusion do not require a bug in your business logic. They only require a front-end component and a back-end component to disagree about where a request starts or what bytes are ignorable. If a proxy or load balancer preserves bytes that Netty drops, the parser leniency itself becomes the primitive.
CVE-2026-50011: RESP array headers should not control heap allocation
The Redis issue is a clean example of “never pre-allocate from attacker-declared length.” NVD describes the original bug simply: RedisArrayAggregator used the array element count declared in the RESP header to size an ArrayList before the child messages even existed on the wire.
The fix adds a configurable ceiling:
public RedisArrayAggregator(int maxElements) {
this.maxElements = ObjectUtil.checkPositive(maxElements, "maxElements");
}
if (header.length() > maxElements) {
throw new CodecException("this codec doesn't support longer length than " + maxElements);
}
Netty also introduced a default property-backed limit:
static final String PROP_REDIS_MAX_ARRAY_LENGTH =
"io.netty.handler.codec.redis.maxArrayLength";
static final int REDIS_MAX_ARRAY_LENGTH =
SystemPropertyUtil.getInt(PROP_REDIS_MAX_ARRAY_LENGTH, 1000000);
That is a meaningful hardening step because the vulnerable shape was cheap for an attacker. A small RESP frame could claim a huge array length and push the JVM into large backing-array allocation immediately, well before a legitimate message tree existed.
This module deserves extra attention because the same release fixed several more Redis codec resource-exhaustion issues. If you expose Redis protocol parsing to untrusted peers, or you use Netty’s Redis codec inside a proxy, gateway, or custom service, upgrading only for CVE-2026-50011 understates the actual risk.
CVE-2026-50560: an HTTP/2 client should not dictate the server’s response budget
The HTTP/2 issue is subtle but operationally important. SETTINGS_MAX_HEADER_LIST_SIZE is advisory from the client’s perspective: it tells the server what the client is willing to receive, not what the server must cap for its own response generation logic.
Before the fix, a hostile client could advertise a tiny value and cause the server’s response-header write path to fail. The patch changes exactly that decision point:
Long maxHeaderListSize = settings.maxHeaderListSize();
if (maxHeaderListSize != null && !connection.isServer()) {
outboundHeaderConfig.maxHeaderListSize(maxHeaderListSize);
}
The new regression test is useful because it demonstrates the exploit shape in a few lines:
http2Client.encoder().writeSettings(
ctx(),
new Http2Settings().maxHeaderListSize(2),
newPromise()
);
Then the server tries to emit a normal :status response and must succeed even though the client claimed it would only accept two bytes of headers. Netty’s own PR explains the impact well: this is “similar to HTTP/2 Rapid Reset, but with a different on-the-wire signature.”
If you terminate HTTP/2 directly in Netty, especially in gateway or proxy roles, that is the right way to think about this bug. It is not a protocol-purity nit. It is a cheap remote resource and error-generation primitive.
Scoping your exposure
Start by identifying whether the affected Netty modules are present at all:
mvn dependency:tree -Dincludes=io.netty:netty-handler,io.netty:netty-codec-http,io.netty:netty-codec-http2,io.netty:netty-codec-redis
./gradlew dependencies --configuration runtimeClasspath | rg "io\\.netty:(netty-handler|netty-codec-http2?|netty-codec-redis)"
Then search for the code paths that make each issue reachable:
rg -n "SslContextBuilder\\.forClient\\(|trustManager\\(" src
rg -n "HttpRequestDecoder|HttpServerCodec|HttpClientCodec|HttpObjectDecoder" src
rg -n "RedisArrayAggregator|RedisDecoder|RedisBulkStringAggregator" src
rg -n "Http2Settings|DefaultHttp2ConnectionEncoder|Http2FrameCodec" src
The hostname-verification issue is the least obvious one to find by runtime behavior alone. You are looking for Netty client TLS contexts that pass a custom trust manager, especially internal SDKs or shared transport libraries that wanted custom trust material but did not intend to disable endpoint checking.
Remediation
Upgrade all Netty artifacts in the affected line together:
- Netty
4.1.x->4.1.135.Final - Netty
4.2.x->4.2.15.Final
Avoid partial upgrades across io.netty:* modules. Netty’s security fixes often land as coordinated changes across handler, codec, and test surfaces, and mixed versions are a good way to trade a known vulnerability for runtime incompatibility.
For prioritization:
- fix any custom client TLS path using
trustManager(...)first; - patch HTTP-facing Netty services next, especially those behind proxies or speaking HTTP/2 directly;
- then patch Redis-protocol consumers and review whether they should ever parse untrusted traffic in the first place.
The broader lesson from this release is that mature transport libraries still define your application’s real attack surface. TLS wrapping, first-line parsing, header-bound enforcement, and decoder pre-allocation are not “framework internals” once untrusted peers can reach them. They are part of the application security boundary, and this June Netty release patched four places where that boundary was too permissive.
References
- Netty 4.1.135.Final release
- Netty 4.2.15.Final release
- Netty news: 4.1.135.Final released
- NVD: CVE-2026-50010
- NVD: CVE-2026-50011
- NVD: CVE-2026-50020
- NVD: CVE-2026-50560
- Netty PR #16868: trust-manager wrapping fix
- Netty PR #16861: HTTP/1.1 initial-line parsing fix
- Netty PR #16858: RedisArrayAggregator bound
- Netty PR #16883: HTTP/2 max-header-list advisory handling