CVE-2026-50020 — netty-codec-http
MEDIUMCVE-2026-50020 is a medium-severity (CVSS 5.3) CWE-444 vulnerability in io.netty:netty-codec-http. A fix is available for io.netty:netty-codec-http — see the affected versions and patch details below.
Netty's HttpObjectDecoder skips arbitrary initial control characters when only initial CRLF characters are permitted
Exploitation Status
Proof-of-concept exploit code exists
- CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
- CISA assesses this as automatable — exploitation doesn’t require manual, per-target effort, which raises the odds of mass scanning and opportunistic attacks.
Exploitation and automatability from CISA’s SSVC triage for CVE-2026-50020.
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
How urgent is this, really
CVE-2026-50020 by exploitation likelihood (EPSS) against impact (CVSS). Outside the shaded patch-first corner.
Where this sits among everything scored
Of 396,257 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Counts from FIRST.org, log-scaled.
Real-World Exposure
io.netty:netty-codec-http☕io.netty:netty-codec-httpReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects Maven packages — download data is not available via public APIs for these ecosystems.
Description
Summary
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.
Affected Code
| File | Lines | Role |
|---|---|---|
codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectDecoder.java | 1298–1313 | ISO_CONTROL_OR_WHITESPACE static initialiser — marks all ISO control chars |
codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectDecoder.java | 1307–1313 | SKIP_CONTROL_CHARS_BYTES ByteProcessor — skips the entire set |
codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectDecoder.java | 1275–1289 | LineParser.skipControlChars — advances readerIndex past all matching bytes |
Specification Analysis
RFC 9112 §2.2 — Message Parsing
In the interest of robustness, a server that is expecting to receive and parse a request-line SHOULD ignore at least one empty line (CRLF) received prior to the request-line.
An HTTP/1.1 user agent MUST NOT preface or follow a request with an extra CRLF.
Deviation
The RFC names a single permitted exception: an empty line (bare CRLF, i.e. the two-byte
sequence \r\n). The ISO_CONTROL_OR_WHITESPACE table is initialised as:
for (byte b = Byte.MIN_VALUE; b < Byte.MAX_VALUE; b++) {
ISO_CONTROL_OR_WHITESPACE[128 + b] =
Character.isISOControl(b) || isWhitespace(b);
}
Character.isISOControl returns true for 0x00–0x1F and 0x7F. This includes NUL
(0x00), SOH (0x01), STX (0x02), BEL (0x07), DEL (0x7F), and every other non-CRLF
control character. The SKIP_CONTROL_CHARS state runs this scan unconditionally before the
first READ_INITIAL, meaning any sequence of such bytes prepended to a request is silently
consumed.
A load balancer or TLS terminator that does not perform the same scan sees a different message boundary than Netty does, which is the basis of a request-desync / smuggling attack.
Suggested Unit Test
Add to HttpRequestDecoderTest.java.
@Test
public void testNonCrlfControlBytesPrecedingRequestLineAreRejected() {
// RFC 9112 §2.2: servers SHOULD ignore "at least one empty line (CRLF)" before the
// request-line. Non-CRLF control bytes are not part of this robustness allowance
// and must not be silently swallowed.
EmbeddedChannel channel = new EmbeddedChannel(new HttpRequestDecoder());
ByteBuf buf = Unpooled.buffer();
buf.writeByte(0x00); // NUL — not an empty CRLF line
buf.writeByte(0x01); // SOH — not an empty CRLF line
buf.writeCharSequence(
"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n",
CharsetUtil.US_ASCII);
channel.writeInbound(buf);
HttpRequest req = channel.readInbound();
// Current behaviour: NUL and SOH are in ISO_CONTROL_OR_WHITESPACE, so they are
// silently skipped; the request decodes successfully and isFailure() == false.
//
// RFC-correct behaviour: only empty CRLF lines should be ignored; NUL/SOH must
// cause a parse error — isFailure() == true.
assertTrue(
req.decoderResult().isFailure(),
"Non-CRLF control bytes before the request-line must not be silently skipped " +
"(RFC 9112 §2.2 allows only empty CRLF lines)");
assertFalse(channel.finish());
}
Current behaviour (unfixed): skipControlChars advances past 0x00 and 0x01 because
both are in ISO_CONTROL_OR_WHITESPACE; the request parses normally, isFailure() is
false → test fails.
Expected behaviour after fix: only CRLF empty lines are tolerated; non-CRLF control
bytes produce an error, isFailure() is true → test passes.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| ☕Maven | io.netty:netty-codec-http | ≥ 4.2.0.Final&&< 4.2.15.Final | 4.2.15.Finalio.netty:netty-codec-http:4.2.15.Final |
| ☕Maven | io.netty:netty-codec-http | all versions | 4.1.135.Finalio.netty:netty-codec-http:4.1.135.Final |
Affected Products
nettynettyDetection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for io.netty:netty-codec-http, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update io.netty:netty-codec-http to 4.2.15.Final or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-50020 is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
Fixing This On Your OS
If you run this on a Linux distribution, patch through your package manager against the distro's own security advisory below — it tracks the exact backported fix for your release, which can ship on a different timeline (and sometimes a different severity) than the upstream project.
This Moderate flaw in Netty's HttpObjectDecoder could lead to data manipulation in Red Hat products utilizing pipelined or multiplexed HTTP transports. The vulnerability arises from the decoder's over-permissive handling of control characters and whitespace, which can cause front-end components to misinterpret HTTP…
Mitigation for this issue is either not available or the currently available options do not meet the Red Hat Product Security criteria comprising ease of use and deployment, applicability to widespread installation base, or stability.Source: Red Hat security advisory for CVE-2026-50020 (CC BY 4.0)
| Product | Fixed in | Advisory |
|---|---|---|
| Red Hat build of Quarkus 3.27.4.SP1 | io.netty/netty-codec-http:4.1.135.Final-redhat-00001 | RHSA-2026:26018 |
| Red Hat build of Quarkus 3.33.2.SP1 | io.netty/netty-codec-http:4.1.135.Final-redhat-00001 | RHSA-2026:26017 |
Frequently Asked Questions
Is CVE-2026-50020 in your dependencies?
Find it across Maven, including transitive dependencies.