CVE-2026-93579: Io.netty/netty-codec-http2: netty: http/2 header field values are not validated by default (cr/lf/nul passthrough)

Published Sep 18, 2026
·
Updated

A flaw was found in Netty's HTTP/2 stack. This vulnerability allows a remote attacker to inject prohibited characters, such as NUL, Line Feed, and Carriage Return, into HTTP/2 header field values due to insufficient validation. When these values cross an HTTP/2 to HTTP/1.1 translation boundary, they can be exploited for request smuggling, header injection, or response splitting. This could lead to unauthorized access, data manipulation, or other security bypasses.

Other sources

HTTP/2 header field values are not validated by default (CR/LF/NUL passthrough)

A public GitHub Security Advisory (GHSA-8whp-c7w8-2m72) describes the following issue:

Summary

Netty's HTTP/2 stack does not validate header field values by default. Genuine prohibited octets — NUL (0x00), LF (0x0A), CR (0x0D) — can be set in an HTTP/2 header value and are carried verbatim to the wire (outbound) and into decoded headers (inbound). This violates RFC 9113 §8.2.1 and becomes an exploitable request-smuggling / header- injection / response-splitting vector at an HTTP/2 ↔ HTTP/1.1 translation boundary.

This report deliberately reframes an earlier report that blamed io.netty.util.AsciiString.c2b(char). c2b is not the problem — see "Non-issue: c2b" below. The real gap is the absence of field-value validation in the HTTP/2 header layer.

Impact

- Severity: depends on deployment. Low on a pure end-to-end HTTP/2 hop (HPACK is length-prefixed, so embedded CR/LF do not split fields on the H2 wire). - Elevated to request smuggling / response splitting whenever a value crosses into HTTP/1.1 (proxy / gateway / adapter) where CR/LF/COLON are delimiters. - RFC 9113 §8.2.1: "Failure to validate fields can be exploited for request smuggling attacks. ... A field value MUST NOT contain the zero value (ASCII NUL, 0x00), line feed (ASCII LF, 0x0a), or carriage return (ASCII CR, 0x0d) at any position." Such messages MUST be treated as malformed, and non-tunnelling intermediaries MUST NOT forward fields containing these octets. RFC 7540 §10.3 has equivalent language.

Root cause: value validation is opt-in and off by default

Header names are validated by default and are not affected: DefaultHttp2Headers HTTP2NAMEVALIDATOR (active when validate=true, the default) runs HttpHeaderValidationUtil.validateToken, which rejects control chars, SP, uppercase, non-ASCII, and (for CharSequence) any char > 0xFF.

Header values are only checked by an opt-in validator that is disabled by default:

- DefaultHttp2Headers() and DefaultHttp2Headers(boolean) install ValueValidator.NOVALIDATION. - Only DefaultHttp2Headers(boolean validate, boolean validateValues, int) installs the real VALUEVALIDATOR (which calls HttpHeaderValidationUtil.validateValidHeaderValue, correctly rejecting < 0x20 except HTAB, and 0x7F — i.e. CR/LF/NUL). - DefaultHttp2HeadersDecoder defaults validateHeaderValues = false. - No public builder exposes value validation. Http2FrameCodecBuilder / AbstractHttp2ConnectionHandlerBuilder.validateHeaders (default true) is wired only to the decoder's name validator, never to value validation and never to the encoder.

The outbound encode path performs no value validation at any stage:

Http2FrameCodec.writeHeadersFrame -> DefaultHttp2ConnectionEncoder.writeHeaders0 (validateHeadersSentState: stream lifecycle only) -> DefaultHttp2FrameWriter.writeHeadersInternal (stream id / padding / weight only) -> DefaultHttp2HeadersEncoder / HpackEncoder.encodeHeaders (serializes as-is)

Because CR (0x0D), LF (0x0A), and NUL (0x00) are all ≤ 255, they survive the char→byte conversion unchanged and are emitted verbatim.

Where it becomes exploitable (H2 → H1.1 translation)

HttpConversionUtil.translateHeaders() copies values with raw output.add(name, value) and performs no CR/LF scan of its own. Whether the prohibited octets are caught depends entirely on whether the destination HTTP/1.1 HttpHeaders has value validation enabled:

- Http2StreamFrameToHttpObjectCodec(boolean isServer) defaults validateHeaders=true → the resulting HTTP/1.1 headers use DEFAULTVALUEVALIDATOR → protected. - InboundHttp2ToHttpAdapter takes validateHttpHeaders from its builder. If set false, an HTTP/2 value containing CR+LF flows verbatim into the HTTP/1.1 message, enabling header injection / request smuggling / response splitting.

Non-issue: AsciiString.c2b() is a clamp, not a security boundary

java private static final char MAXCHARVALUE = 255; public static byte c2b(char c) { return (byte) ((c > MAXCHARVALUE) ? '?' : c); }

The earlier report proposed changing c2b. That is misdirected:

1. C1 control passthrough (0x80–0x9F) is spec-compliant. These octets are obs-text (%x80–FF), valid in field values. HPACK is length-prefixed, so they are never delimiters on the HTTP/2 wire. No action needed. 2. The > 255 → '?' replacement is protective, not harmful. It prevents the "ghost bits" truncation attack: were c2b to truncate raw (as the private, unreachable c2b0 does), \u010A (266) would become 0x0A (LF) and \u010D (269) would become 0x0D (CR) on the wire — actual injection. The clamp closes that hole. The proposed "reject C1 in c2b" change adds no security and would break obs-text. 3. The silent ? substitution of > 255 chars is at most a correctness/interop concern (application String vs. wire bytes mismatch); it makes values safer, not more dangerous, and is not a vulnerability.

Fixing c2b neither addresses the real gap nor is necessary. The fix belongs in the HTTP/2 header layer.

Affected code

- io.netty.handler.codec.http2.DefaultHttp2Headers — value validator off in the common constructors. - io.netty.handler.codec.http2.DefaultHttp2HeadersDecoder — validateHeaderValues defaults to false. - io.netty.handler.codec.http2.Http2FrameCodecBuilder / AbstractHttp2ConnectionHandlerBuilder — no way to enable value validation; the validateHeaders flag reaches only the decoder's name check. - Outbound: DefaultHttp2ConnectionEncoder, DefaultHttp2FrameWriter, HpackEncoder — no value validation on encode. - Translation: HttpConversionUtil.translateHeaders, InboundHttp2ToHttpAdapter (when validateHttpHeaders=false).

Suggested fix

1. Validate HTTP/2 field values against RFC 9113 §8.2.1 — reject NUL (0x00), LF (0x0A), CR (0x0D) at any position (the logic alread

[truncated]

Affected: - maven:io.netty:netty-codec-http2 affected >= 4.2.0.Final, <=4.2.17.Final; fixed unknown - maven:io.netty:netty-codec-http2 affected <=4.1.137.Final; fixed unknown

Fixed versions: see advisory

Advisory: https://github.com/netty/netty/security/advisories/GHSA-8whp-c7w8-2m72

Red Hat

Affected Software

2 affected components
io.netty maven/io.netty/netty-codec-http2>=4.2.0.Final<=4.2.17.Final
io.netty maven/io.netty/netty-codec-http2<=4.1.137.Final

Event History

Sep 18, 2026
Data Sourced
via Red Hat·10:36 AM
DescriptionSeverityAffected Software
CVE Published
via MITRE·04:38 PM
Data Sourced
via MITRE·04:38 PM
DescriptionSeverityWeakness

Frequently Asked Questions

1

Which deployments are most exposed?

Deployments with an HTTP/2 to HTTP/1.1 translation boundary are the relevant exposure point. At that boundary, unvalidated NUL, LF, or CR characters in HTTP/2 header values can enable request smuggling, header injection, or response splitting.

2

Does exploitation require authentication or user interaction?

No. The supplied severity vector indicates network access with low attack complexity and no required privileges or user interaction.

3

Is the unsafe behavior enabled by default?

Yes. Netty's HTTP/2 stack does not validate header field values by default, allowing NUL, LF, and CR bytes to pass through outbound headers and decoded inbound headers.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203