GitHub Advisoryadvisory · Maven
GHSA-cm33-6792-r9fm Netty has a DNS Codec Input Validation Bypass (Encoder + Decoder)
HIGH
Official page ↗
- Aliases
- CVE-2026-42579
- Ecosystem
- Maven
- Packages
- io.netty:netty-codec-dns
- Severity
- High
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
- Weaknesses
- CWE-20, CWE-400, CWE-626
- Reviewed
- 2026-05-07
Affected packages
• Maven io.netty:netty-codec-dns: >= 4.2.0.Alpha1, < 4.2.13.Final → fixed in 4.2.13.Final
• Maven io.netty:netty-codec-dns: < 4.1.133.Final → fixed in 4.1.133.Final
Description
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)` 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] Nul…
Related
Alias · CVE (1)
- CVE-2026-42579 Netty is an asynchronous, event-driven network application framework. vulnerability