Netty provides low-level asynchronous network primitives and protocol codecs that require developers to explicitly enforce strict input bounds, cryptographic verification, and resource management. The library protects transport mechanics and channel lifecycles by default, but does not sanitize application payloads, validate complex routing logic, or restrict dynamic deserialization without developer configuration. Security-sensitive surfaces include protocol decoders, channel pipelines, SSL contexts, and file handlers, all of which must fail closed when encountering malformed inputs, authorization rejections, or resource anomalies.
Essential implementation rules
Enforce Strict Inbound Protocol and Payload Bounds
Configure explicit protocol limits using HttpDecoderConfig or length-field decoders with explicit bounds such as max initial line length, header size, and payload limits. Always verify buffer read indexes before parsing frames and reject oversized or malformed inputs before downstream processing.
Secure Object Deserialization and Unmarshalling
Avoid legacy Java serialization codecs. When unmarshalling untrusted data streams, enforce JVM-level jdk.serialFilter allowlists or custom ClassResolvers and provide strict byte-size limits on decoders like CompatibleMarshallingDecoder and ObjectDecoder to prevent remote code execution and memory exhaustion.
Configure Robust Transport Security and Mutual TLS
Construct server and client SSL contexts using SslContextBuilder with restricted secure protocols (TLSv1.2 and TLSv1.3) and strong cipher suites. Enable endpoint hostname verification and require mutual TLS explicitly via client authentication configuration on server and QUIC contexts.
Isolate Authorization State and Handle Connection Rejections Securely
Scope stateful authorization flags to individual connections using AttributeKey references within @Sharable channel handlers. Inspect proxy connection futures for authorization failures and ensure connections fail closed without attempting unsafe fallbacks.
Sanitize Pipeline Exceptions and Logging Telemetry
Override exceptionCaught in channel handlers to cleanly record failures and close affected channels or propagate exceptions explicitly without discarding them. Use ByteBufFormat.SIMPLE in LoggingHandler instances to prevent raw sensitive payload leakage in logs.
Validate Paths and Manage Multipart File Upload Lifecycles
Validate and normalize request paths and file names to prevent traversal bypasses before accessing disk resources or streaming files. Configure isolated base directories for HTTP uploads, set strict size limits on multipart data, and explicitly destroy decoders or delete temporary files in try-finally blocks.
Harden Runtime Native Libraries and Platform Capabilities
Configure io.netty.native.workdir to point to a process-private filesystem directory for JNI dynamic library extractions with permissions restricted to the application execution context. Set JVM properties such as -Dio.netty.noUnsafe=true when running in sandboxed security manager environments.
Bind Local Boundaries and Enforce Resource Exhaustion Controls
Bind local servers and datagram channels explicitly to loopback addresses like 127.0.0.1 instead of wildcard interfaces. Enforce peer certificate chain size limits, configure maximum idle timeouts on QUIC builders, and set explicit non-zero bounds for session cache sizes and timeouts.
netty: All Security Cards
Approximately 6,234 tokens
On this card
Category: access control
Secure Channel Authorization and Proxy Connection Handling
Use when
Implementing custom Netty ChannelHandler authorization logic or managing outbound proxy connections via HttpProxyHandler or Socks5ProxyHandler.
Secure rules
Rule 1: Fail securely upon receiving proxy connection authorization rejections.
When routing network traffic through proxy handlers, inspect connection futures for ProxyConnectException to catch HTTP 403 or SOCKS FORBIDDEN statuses. Reject the connection securely and do not attempt unsafe fallbacks to unproxied access.
bootstrap.connect(destinationAddress).addListener((ChannelFuture future) -> { if (!future.isSuccess()) { Throwable cause = future.cause(); if (cause instanceof ProxyConnectException) { logger.error("Proxy connection authorization denied: {}", cause.getMessage()); } }});
Rule 2: Isolate authorization state per channel in shared channel handlers.
When implementing authorization checks inside custom ChannelHandler implementations, ensure stateful authorization flags are scoped to individual connections. When sharing a handler instance marked with @Sharable, store authorization state exclusively via ChannelHandlerContext attributes using AttributeKey.
@Sharablepublic class AuthorizedDataHandler extends SimpleChannelInboundHandler<DataMessage> { private static final AttributeKey<Boolean> IS_AUTHORIZED = AttributeKey.valueOf("is_authorized"); @Override protected void channelRead0(ChannelHandlerContext ctx, DataMessage msg) { if (msg.isAuthToken()) { ctx.attr(IS_AUTHORIZED).set(verifyPermissions(msg.getToken())); } else { if (Boolean.TRUE.equals(ctx.attr(IS_AUTHORIZED).get())) { ctx.writeAndFlush(fetchData(msg)); } else { throw new SecurityException("Unauthorized data access attempt"); } } }}
Category: api contract misuse
Sanitize Pipeline Exceptions and Avoid Exposing Raw Error Details
Use when
Developing or maintaining channel handlers in Netty pipelines that process inbound and outbound events and handle uncaught exceptions.
Secure rules
Rule 1: Handle pipeline exceptions and close failed channels in exceptionCaught
Override exceptionCaught when a handler must terminate a connection after an exception. Record the exception for diagnosis and call ctx.close() to close the affected channel.
Rule 2: Handle or explicitly propagate exceptions in exceptionCaught
When overriding exceptionCaught, either handle the failure and close the affected channel or forward the exception to the next pipeline handler with ctx.fireExceptionCaught(cause). Do not silently discard the exception.
Use SslContextBuilder for Secure SSL Context Initialization
Use when
Building TLS server or client SSL contexts in Netty applications and avoiding deprecated factory methods or direct constructor instantiation.
Secure rules
Rule 1: Construct SSL contexts using SslContextBuilder rather than deprecated static factory methods or direct constructor calls.
Use SslContextBuilder to configure server and client contexts correctly, providing required options and avoiding legacy factory methods and direct constructors like JdkSslServerContext that lack centralized parameter validation and proper security defaults.
Validate Client Certificates for QUIC Server Connections
Use when
Configuring mutual TLS (mTLS) authentication for QUIC servers in Netty to ensure connecting clients are properly authenticated.
Secure rules
Rule 1: Require mutual TLS client authentication explicitly on QUIC server contexts.
Set clientAuth(ClientAuth.REQUIRE) and provide trusted certificates via trustManager(...) when building server contexts to prevent unauthenticated client access.
Configure Secure TLS Protocols, Cipher Suites, and Endpoint Verification
Use when
Configuring SslContext and client connections for Netty secure communications.
Secure rules
Rule 1: Enable TLS hostname verification and configure strong protocols and cipher suites.
Keep TLS endpoint verification enabled for client connections and avoid setting io.netty.handler.ssl.defaultEndpointVerificationAlgorithm to NONE. Explicitly restrict SSL/TLS contexts to secure protocols such as TLSv1.2 and TLSv1.3 and strong, authenticated cipher suites when building SslContext instances.
Secure Dynamic Class Resolution and Native Library Loading
Use when
Configuring class resolution for dynamic loading or setting up native library working directories in Netty applications.
Secure rules
Rule 1: Allowlist classes when using Netty Java deserialization
Avoid Netty’s deprecated Java-serialization codecs where possible. When they must be used, configure a jdk.serialFilter allowlist that permits only the classes expected by the application before accepting serialized objects. Supplying a particular ClassLoader to a ClassResolver does not replace deserialization filtering.
Rule 2: Configure a secure native working directory for dynamic JNI library extraction
When Netty dynamically extracts and loads JNI dynamic libraries, configure the native working directory using io.netty.native.workdir to point to a secure location accessible only by the application execution context. Avoid defaulting to world-writable temporary directories where local users could tamper with binaries prior to dynamic loading.
Rule 3: Retain automatic deletion of extracted native libraries after loading
Leave io.netty.native.deleteLibAfterLoading unset or set it to true. Netty enables this behavior by default, deletes an extracted native-library file after loading to free resources, and schedules deletion at JVM exit when immediate deletion is disabled or unsuccessful.
Enforce Strict Size Limits During Object Unmarshalling
Use when
When configuring decoders like CompatibleMarshallingDecoder to unmarshal network byte streams into Java objects.
Secure rules
Rule 1: Configure an explicit maximum object size limit when unmarshalling untrusted byte streams to prevent memory exhaustion.
When using CompatibleMarshallingDecoder, avoid using Integer.MAX_VALUE or unlimited sizes for object unmarshalling. Supply a strict byte size limit to CompatibleMarshallingDecoder to ensure that payload boundaries are validated before binding input bytes into Java object graphs.
int maxObjectSize = 1024 * 1024;ChannelHandler decoder = new CompatibleMarshallingDecoder( new DefaultUnmarshallerProvider(marshallerFactory, marshallingConfig), maxObjectSize);pipeline.addLast(decoder);
Secure Object Deserialization and Enforce Payload Bounds
Use when
Configuring Netty serialization decoders such as ObjectDecoder and ObjectDecoderInputStream to process Java object streams from untrusted network sources.
Secure rules
Rule 1: Enforce JVM-level serialization filters and custom allowlists to restrict deserialized classes.
When using ObjectDecoder, ObjectDecoderInputStream, or ClassResolvers, avoid unrestricted object deserialization. Configure JVM-level serialization filters via the jdk.serialFilter system property or supply a custom ClassResolver to explicitly allowlist expected safe classes and prevent remote code execution through gadget chains.
Set<String> ALLOWED_CLASSES = Set.of("com.example.MyDataDTO");ClassResolver safeResolver = className -> { if (!ALLOWED_CLASSES.contains(className)) { throw new ClassNotFoundException("Class deserialization restricted: " + className); } return Class.forName(className);};CompactObjectInputStream in = new CompactObjectInputStream(inputStream, safeResolver);
Rule 2: Configure explicit maximum object size limits on decoders to prevent memory exhaustion.
Always provide an explicit maxObjectSize parameter when instantiating ObjectDecoder or ObjectDecoderInputStream to constrain incoming object frame lengths and stop oversized payloads from triggering OutOfMemoryError exceptions.
int maxObjectSize = 1048576; // 1 MB limitpipeline.addLast(new ObjectDecoder(maxObjectSize, ClassResolvers.weakCachingConcurrentResolver(getClass().getClassLoader())));
Category: escape hatch
Secure Internal Reflection and Dynamic Class Loading
Use when
Use when performing reflective access to internal classes, constructors, or fields, or when dynamically loading providers via reflection.
Secure rules
Rule 1: Guard reflective lookups and field accessibility changes inside controlled privileged blocks and catch access or reflection exceptions.
When using reflection to access non-public members, internal constructors, or system classes, wrap operations in controlled blocks and catch exceptions like NoSuchMethodException or IllegalAccessException to prevent fatal runtime failures.
Object result = AccessController.doPrivileged((PrivilegedAction<Object>) () -> { try { Field field = TargetClass.getDeclaredField("privateField"); Throwable cause = ReflectionUtil.trySetAccessible(field, false); if (cause != null) { return cause; } return field.get(targetInstance); } catch (NoSuchFieldException | IllegalAccessException | SecurityException e) { return e; }});
Rule 2: Restrict dynamic reflection to hardcoded fully qualified class names.
When using reflection to dynamically load and instantiate security providers or engine classes, restrict class lookup exclusively to hardcoded, fully-qualified internal constants. Do not pass untrusted or externally controlled class names.
Secure Multipart Upload Storage and Temporary File Lifecycle Management
Use when
Handling incoming HTTP multipart form uploads, file uploads, and temporary attributes in Netty.
Secure rules
Rule 1: Configure isolated base directories for HTTP file uploads
Use DefaultHttpDataFactory.setBaseDir or configure DiskFileUpload.baseDirectory and DiskAttribute.baseDirectory to point to dedicated directories protected by appropriate operating system access controls instead of relying on default system-wide temporary directories.
DefaultHttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE);factory.setBaseDir("/var/app/data/secure_tmp");
Rule 2: Clean up multipart temporary disk files after processing requests
Explicitly call cleanup methods such as cleanRequestHttpData, cleanAllHttpData, decoder.destroy(), or decoder.cleanFiles() in a try-finally block after completing multipart HTTP request processing to ensure temporary disk files and buffers are immediately deleted.
HttpPostMultipartRequestDecoder decoder = new HttpPostMultipartRequestDecoder(factory, request);try { // Process multipart request data} finally { decoder.destroy();}
Rule 3: Sanitize destination paths and manage temporary file retention
When persisting uploaded HTTP data using HttpData.renameTo, validate that target destination paths reside within expected directory boundaries and explicitly manage temporary file retention. Calling renameTo removes the file from the automatic factory cleaner, making explicit deletion imperative.
Rule 4: Enforce size limits on HTTP multipart file uploads
Explicitly configure maximum size limits using setMaxSize(long) on Netty multipart HttpData instances to prevent excessive resource consumption and storage exhaustion.
Mapping HTTP request URIs to disk files and streaming static files or large content in Netty servers.
Secure rules
Rule 1: Validate request paths before opening or serving files
Validate and decode request-derived paths before constructing or opening files. Reject invalid or unsafe paths before file access, and do not rely on the simplistic path checks in Netty’s static-file example for production use.
Rule 2: Manage file channels and zero copy transfers safely
Select the appropriate transfer mechanism based on TLS configuration. Use DefaultFileRegion for zero-copy file transfer over plain connections, and use ChunkedFile wrapped in HttpChunkedInput when SSL/TLS is active so that SslHandler can encrypt the outbound payload.
Rule 3: Stream large static files using chunked input handlers
Open underlying files in read-only mode and pass the RandomAccessFile to ChunkedFile inside chunked input wrappers to stream file content asynchronously in fixed-size chunks rather than loading entire files into memory.
RandomAccessFile raf = new RandomAccessFile(file, "r");long fileLength = raf.length();Http2DataChunkedInput chunkedInput = new Http2DataChunkedInput( new ChunkedFile(raf, 0, fileLength, 8192), stream);ctx.writeAndFlush(chunkedInput, ctx.newProgressivePromise());
Category: input interpretation safety
Enforce Strict Input Size Bounds and Protocol Parsing Limits
Use when
Configuring network protocol decoders, HTTP codecs, and frame decoders to ingest untrusted data safely.
Secure rules
Rule 1: Configure explicit size bounds and header limits on inbound protocol decoders.
Use configuration classes like HttpDecoderConfig with explicit bounds such as setMaxInitialLineLength, setMaxHeaderSize, and setMaxChunkSize, or pass explicit limits into protocol decoders like StompSubframeDecoder, MqttDecoder, and LengthFieldBasedFrameDecoder to reject oversized or malformed payloads before downstream processing.
HttpDecoderConfig config = new HttpDecoderConfig() .setInitialBufferSize(1024) .setMaxInitialLineLength(4096) .setMaxHeaderSize(8192) .setMaxChunkSize(8192);HttpRequestDecoder decoder = new HttpRequestDecoder(config);
Rule 2: Enforce strict header validation, canonicalization, and parsing checks.
Ensure decoders maintain strict validation defaults, such as enabling setValidateHeaders(true), rejecting duplicate content lengths via setAllowDuplicateContentLengths(false), enabling strict line parsing, and restricting UTF-8 string validation to reject malformed sequences, null characters, and injection vectors.
HttpDecoderConfig config = new HttpDecoderConfig() .setValidateHeaders(true) .setAllowDuplicateContentLengths(false) .setStrictLineParsing(true) .setUseRfc9112TransferEncoding(true);
Verify that input buffers contain sufficient readable bytes before parsing frames, handle null return values for truncated packets, check decoder result flags like decoderResult().isFailure() or frame invalidity flags, and catch decoding exceptions to terminate sessions securely.
public class FrameDecoder extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { if (in.readableBytes() < 4) { return; } int length = in.getInt(in.readerIndex()); if (in.readableBytes() < 4 + length) { return; } in.skipBytes(4); out.add(in.readRetainedSlice(length)); }}
Validate and Normalize Request Targets and Paths During Routing and Deep Link Resolution
Use when
Handling inbound HTTP requests, converting protocol headers, or parsing deep link URIs for routing and parameter extraction.
Secure rules
Rule 1: Inspect raw path components or sanitize decoded paths prior to route matching to prevent path ambiguity and traversal bypasses.
When using QueryStringDecoder, remember that decoder.path() automatically decodes percent-encoded characters while decoder.rawPath() preserves the original encoding. Route matching logic should inspect raw paths or explicitly normalize decoded paths, accounting for matrix parameters and boundary tokens.
Rule 2: Strictly validate converted HTTP/2 pseudo-headers before passing target paths to downstream routing components.
When converting HTTP/1.x requests to HTTP/2 headers using HttpConversionUtil.toHttp2Headers, enable header validation and verify that the resulting :path pseudo-header complies with expected origin-form routing constraints to prevent routing mismatches across protocol translation layers.
Safely Manage Reference-Counted OpenSSL Contexts and Engines
Use when
Managing the lifecycle of Netty’s ReferenceCountedOpenSslContext and ReferenceCountedOpenSslEngine native resources.
Secure rules
Rule 1: Ensure OpenSSL engines are released before releasing their parent OpenSSL context to prevent native use-after-free access.
Explicitly manage the lifecycle of ReferenceCountedOpenSslEngine instances by invoking release() when they are no longer needed, ensuring all child engines are shut down and released prior to releasing the parent ReferenceCountedOpenSslContext.
Secure Inter-Process and Inter-Component Network Boundaries and Peer Authentication
Use when
Developing local inter-process communication (IPC) channels, server sockets, or datagram connections using Netty transports that require strict interface isolation and peer validation.
Secure rules
Rule 1: Explicitly bind local server and datagram channels to loopback addresses rather than wildcard interfaces.
When configuring Netty ServerBootstrap or datagram channels for inter-process communication, avoid wildcard addresses like 0.0.0.0. Bind explicitly to loopback addresses such as 127.0.0.1 or NetUtil.LOCALHOST to prevent exposing internal IPC channels to external network interfaces.
InetSocketAddress localAddress = new InetSocketAddress("127.0.0.1", port);ChannelFuture f = sb.bind(localAddress).sync();
Rule 2: Authenticate local IPC peer processes on Unix domain datagram sockets.
When performing inter-process communication via EpollDomainDatagramChannel over Unix domain sockets, authenticate peer processes by inspecting peer credentials retrieved through peerCredentials() before trusting incoming datagrams.
Rule 3: Enforce QUIC address validation in production network services.
When configuring HTTP/3 or QUIC server endpoints for inter-process or inter-component communication, avoid using InsecureQuicTokenHandler.INSTANCE, which skips address validation tokens and enables UDP amplification attacks. Always configure a validating QuicTokenHandler implementation for production deployments.
Validate HTTP Header Values and Control Characters in Netty Codecs
Use when
Use when constructing HTTP/2 headers or translating HTTP/1.x objects to HTTP/2 frames to prevent header injection and control character smuggling.
Secure rules
Rule 1: Enable value validation when constructing HTTP/2 headers from untrusted values
When adding untrusted values to DefaultHttp2Headers, use the three-argument constructor with both header-name and header-value validation enabled. The second boolean enables rejection of prohibited characters such as NUL, CR, LF, DEL, and other control characters.
Http2Headers headers = new DefaultHttp2Headers(true, true, 16);headers.add("x-custom-header", userProvidedValue);
Rule 2: Enable validateHeaders during outbound conversion from HTTP/1.x objects to HTTP/2 frames.
Pass validateHeaders as true when instantiating HttpToHttp2ConnectionHandler so that HttpConversionUtil.toHttp2Headers checks header names, values, and control characters, blocking improper header content from being emitted in outbound traffic.
Configure Connection Idle Timeouts and Certificate Limits to Prevent Resource Exhaustion
Use when
Setting up Netty network services, QUIC servers, or SSL contexts where malicious clients could trigger resource exhaustion or memory denial-of-service.
Secure rules
Rule 1: Enforce maximum peer certificate chain size limits on OpenSSL-backed SSL contexts.
When configuring Netty’s OpenSSL-backed SSL context, enforce limits on the maximum accepted peer certificate chain size by setting OpenSslContextOption.MAX_CERTIFICATE_LIST_BYTES on SslContextBuilder to prevent excessive memory allocation during TLS handshakes.
Rule 2: Configure maximum idle timeouts on QUIC server and client builders.
Explicitly configure a maximum idle timeout on QuicServerBuilder and QuicClientBuilder instances using maxIdleTimeout() to ensure abandoned connections are properly cleaned up and do not remain allocated in memory indefinitely.
Rule 2: Bind worker threads explicitly to a designated ThreadGroup using DefaultThreadFactory.
Pass an explicit ThreadGroup parameter when instantiating DefaultThreadFactory to enforce distinct execution boundaries instead of inheriting the caller thread group dynamically.
ThreadGroup isolatedGroup = new ThreadGroup("isolated-workers");DefaultThreadFactory factory = new DefaultThreadFactory( "worker-pool", false, Thread.NORM_PRIORITY, isolatedGroup);Thread worker = factory.newThread(task);
Set the JVM system property -Dio.netty.noUnsafe=true when launching applications in secure environments to prevent dynamic acquisition of sun.misc.Unsafe capabilities.
Rule 4: Restrict native library extraction work directory permissions to a private, secure path.
Configure the io.netty.native.workdir system property to point to a dedicated, process-private directory with restricted filesystem permissions and native execution support.
Sanitize Logging and Telemetry Hints to Prevent Sensitive Data Disclosure
Use when
Configuring network channel logging or resource leak tracking mechanisms that process user payloads or telemetry.
Secure rules
Rule 1: Configure LoggingHandler with ByteBufFormat.SIMPLE to prevent raw payload leakage.
Use ByteBufFormat.SIMPLE when instantiating LoggingHandler in environments processing sensitive network data to ensure only byte sizes rather than full hex dumps of payload contents are written to log files.
LoggingHandler handler = new LoggingHandler(LogLevel.INFO, ByteBufFormat.SIMPLE);channel.pipeline().addLast(handler);
Category: session management
Configure Explicit SSL Session Cache Limits and Timeouts
Use when
When instantiating server SSL contexts and setting explicit upper bounds for session cache size and timeouts to prevent unbounded memory consumption from cached TLS sessions.
Secure rules
Rule 1: Set explicit non-zero upper bounds for sessionCacheSize and sessionTimeout on the server SSL session context.
When instantiating server SSL contexts using SslContextBuilder, configure sessionCacheSize and sessionTimeout with explicit values to prevent unbounded memory consumption from cached TLS sessions.
Secure Channel Authorization and Proxy Connection Handling
Approximately 432 tokens
Use when
Implementing custom Netty ChannelHandler authorization logic or managing outbound proxy connections via HttpProxyHandler or Socks5ProxyHandler.
Secure rules
Rule 1: Fail securely upon receiving proxy connection authorization rejections.
When routing network traffic through proxy handlers, inspect connection futures for ProxyConnectException to catch HTTP 403 or SOCKS FORBIDDEN statuses. Reject the connection securely and do not attempt unsafe fallbacks to unproxied access.
bootstrap.connect(destinationAddress).addListener((ChannelFuture future) -> { if (!future.isSuccess()) { Throwable cause = future.cause(); if (cause instanceof ProxyConnectException) { logger.error("Proxy connection authorization denied: {}", cause.getMessage()); } }});
Rule 2: Isolate authorization state per channel in shared channel handlers.
When implementing authorization checks inside custom ChannelHandler implementations, ensure stateful authorization flags are scoped to individual connections. When sharing a handler instance marked with @Sharable, store authorization state exclusively via ChannelHandlerContext attributes using AttributeKey.
@Sharablepublic class AuthorizedDataHandler extends SimpleChannelInboundHandler<DataMessage> { private static final AttributeKey<Boolean> IS_AUTHORIZED = AttributeKey.valueOf("is_authorized"); @Override protected void channelRead0(ChannelHandlerContext ctx, DataMessage msg) { if (msg.isAuthToken()) { ctx.attr(IS_AUTHORIZED).set(verifyPermissions(msg.getToken())); } else { if (Boolean.TRUE.equals(ctx.attr(IS_AUTHORIZED).get())) { ctx.writeAndFlush(fetchData(msg)); } else { throw new SecurityException("Unauthorized data access attempt"); } } }}
Sanitize Pipeline Exceptions and Avoid Exposing Raw Error Details
Approximately 433 tokens
Use when
Developing or maintaining channel handlers in Netty pipelines that process inbound and outbound events and handle uncaught exceptions.
Secure rules
Rule 1: Handle pipeline exceptions and close failed channels in exceptionCaught
Override exceptionCaught when a handler must terminate a connection after an exception. Record the exception for diagnosis and call ctx.close() to close the affected channel.
Rule 2: Handle or explicitly propagate exceptions in exceptionCaught
When overriding exceptionCaught, either handle the failure and close the affected channel or forward the exception to the next pipeline handler with ctx.fireExceptionCaught(cause). Do not silently discard the exception.
Use SslContextBuilder for Secure SSL Context Initialization
Use when
Building TLS server or client SSL contexts in Netty applications and avoiding deprecated factory methods or direct constructor instantiation.
Secure rules
Rule 1: Construct SSL contexts using SslContextBuilder rather than deprecated static factory methods or direct constructor calls.
Use SslContextBuilder to configure server and client contexts correctly, providing required options and avoiding legacy factory methods and direct constructors like JdkSslServerContext that lack centralized parameter validation and proper security defaults.
Validate Client Certificates for QUIC Server Connections
Approximately 191 tokens
Use when
Configuring mutual TLS (mTLS) authentication for QUIC servers in Netty to ensure connecting clients are properly authenticated.
Secure rules
Rule 1: Require mutual TLS client authentication explicitly on QUIC server contexts.
Set clientAuth(ClientAuth.REQUIRE) and provide trusted certificates via trustManager(...) when building server contexts to prevent unauthenticated client access.
Configure Secure TLS Protocols, Cipher Suites, and Endpoint Verification
Approximately 264 tokens
Use when
Configuring SslContext and client connections for Netty secure communications.
Secure rules
Rule 1: Enable TLS hostname verification and configure strong protocols and cipher suites.
Keep TLS endpoint verification enabled for client connections and avoid setting io.netty.handler.ssl.defaultEndpointVerificationAlgorithm to NONE. Explicitly restrict SSL/TLS contexts to secure protocols such as TLSv1.2 and TLSv1.3 and strong, authenticated cipher suites when building SslContext instances.
Secure Dynamic Class Resolution and Native Library Loading
Approximately 373 tokens
Use when
Configuring class resolution for dynamic loading or setting up native library working directories in Netty applications.
Secure rules
Rule 1: Allowlist classes when using Netty Java deserialization
Avoid Netty’s deprecated Java-serialization codecs where possible. When they must be used, configure a jdk.serialFilter allowlist that permits only the classes expected by the application before accepting serialized objects. Supplying a particular ClassLoader to a ClassResolver does not replace deserialization filtering.
Rule 2: Configure a secure native working directory for dynamic JNI library extraction
When Netty dynamically extracts and loads JNI dynamic libraries, configure the native working directory using io.netty.native.workdir to point to a secure location accessible only by the application execution context. Avoid defaulting to world-writable temporary directories where local users could tamper with binaries prior to dynamic loading.
Rule 3: Retain automatic deletion of extracted native libraries after loading
Leave io.netty.native.deleteLibAfterLoading unset or set it to true. Netty enables this behavior by default, deletes an extracted native-library file after loading to free resources, and schedules deletion at JVM exit when immediate deletion is disabled or unsuccessful.
Enforce Strict Size Limits During Object Unmarshalling
Approximately 555 tokens
Use when
When configuring decoders like CompatibleMarshallingDecoder to unmarshal network byte streams into Java objects.
Secure rules
Rule 1: Configure an explicit maximum object size limit when unmarshalling untrusted byte streams to prevent memory exhaustion.
When using CompatibleMarshallingDecoder, avoid using Integer.MAX_VALUE or unlimited sizes for object unmarshalling. Supply a strict byte size limit to CompatibleMarshallingDecoder to ensure that payload boundaries are validated before binding input bytes into Java object graphs.
int maxObjectSize = 1024 * 1024;ChannelHandler decoder = new CompatibleMarshallingDecoder( new DefaultUnmarshallerProvider(marshallerFactory, marshallingConfig), maxObjectSize);pipeline.addLast(decoder);
Secure Object Deserialization and Enforce Payload Bounds
Use when
Configuring Netty serialization decoders such as ObjectDecoder and ObjectDecoderInputStream to process Java object streams from untrusted network sources.
Secure rules
Rule 1: Enforce JVM-level serialization filters and custom allowlists to restrict deserialized classes.
When using ObjectDecoder, ObjectDecoderInputStream, or ClassResolvers, avoid unrestricted object deserialization. Configure JVM-level serialization filters via the jdk.serialFilter system property or supply a custom ClassResolver to explicitly allowlist expected safe classes and prevent remote code execution through gadget chains.
Set<String> ALLOWED_CLASSES = Set.of("com.example.MyDataDTO");ClassResolver safeResolver = className -> { if (!ALLOWED_CLASSES.contains(className)) { throw new ClassNotFoundException("Class deserialization restricted: " + className); } return Class.forName(className);};CompactObjectInputStream in = new CompactObjectInputStream(inputStream, safeResolver);
Rule 2: Configure explicit maximum object size limits on decoders to prevent memory exhaustion.
Always provide an explicit maxObjectSize parameter when instantiating ObjectDecoder or ObjectDecoderInputStream to constrain incoming object frame lengths and stop oversized payloads from triggering OutOfMemoryError exceptions.
int maxObjectSize = 1048576; // 1 MB limitpipeline.addLast(new ObjectDecoder(maxObjectSize, ClassResolvers.weakCachingConcurrentResolver(getClass().getClassLoader())));
Secure Internal Reflection and Dynamic Class Loading
Approximately 373 tokens
Use when
Use when performing reflective access to internal classes, constructors, or fields, or when dynamically loading providers via reflection.
Secure rules
Rule 1: Guard reflective lookups and field accessibility changes inside controlled privileged blocks and catch access or reflection exceptions.
When using reflection to access non-public members, internal constructors, or system classes, wrap operations in controlled blocks and catch exceptions like NoSuchMethodException or IllegalAccessException to prevent fatal runtime failures.
Object result = AccessController.doPrivileged((PrivilegedAction<Object>) () -> { try { Field field = TargetClass.getDeclaredField("privateField"); Throwable cause = ReflectionUtil.trySetAccessible(field, false); if (cause != null) { return cause; } return field.get(targetInstance); } catch (NoSuchFieldException | IllegalAccessException | SecurityException e) { return e; }});
Rule 2: Restrict dynamic reflection to hardcoded fully qualified class names.
When using reflection to dynamically load and instantiate security providers or engine classes, restrict class lookup exclusively to hardcoded, fully-qualified internal constants. Do not pass untrusted or externally controlled class names.
Secure Multipart Upload Storage and Temporary File Lifecycle Management
Approximately 971 tokens
Use when
Handling incoming HTTP multipart form uploads, file uploads, and temporary attributes in Netty.
Secure rules
Rule 1: Configure isolated base directories for HTTP file uploads
Use DefaultHttpDataFactory.setBaseDir or configure DiskFileUpload.baseDirectory and DiskAttribute.baseDirectory to point to dedicated directories protected by appropriate operating system access controls instead of relying on default system-wide temporary directories.
DefaultHttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE);factory.setBaseDir("/var/app/data/secure_tmp");
Rule 2: Clean up multipart temporary disk files after processing requests
Explicitly call cleanup methods such as cleanRequestHttpData, cleanAllHttpData, decoder.destroy(), or decoder.cleanFiles() in a try-finally block after completing multipart HTTP request processing to ensure temporary disk files and buffers are immediately deleted.
HttpPostMultipartRequestDecoder decoder = new HttpPostMultipartRequestDecoder(factory, request);try { // Process multipart request data} finally { decoder.destroy();}
Rule 3: Sanitize destination paths and manage temporary file retention
When persisting uploaded HTTP data using HttpData.renameTo, validate that target destination paths reside within expected directory boundaries and explicitly manage temporary file retention. Calling renameTo removes the file from the automatic factory cleaner, making explicit deletion imperative.
Rule 4: Enforce size limits on HTTP multipart file uploads
Explicitly configure maximum size limits using setMaxSize(long) on Netty multipart HttpData instances to prevent excessive resource consumption and storage exhaustion.
Mapping HTTP request URIs to disk files and streaming static files or large content in Netty servers.
Secure rules
Rule 1: Validate request paths before opening or serving files
Validate and decode request-derived paths before constructing or opening files. Reject invalid or unsafe paths before file access, and do not rely on the simplistic path checks in Netty’s static-file example for production use.
Rule 2: Manage file channels and zero copy transfers safely
Select the appropriate transfer mechanism based on TLS configuration. Use DefaultFileRegion for zero-copy file transfer over plain connections, and use ChunkedFile wrapped in HttpChunkedInput when SSL/TLS is active so that SslHandler can encrypt the outbound payload.
Rule 3: Stream large static files using chunked input handlers
Open underlying files in read-only mode and pass the RandomAccessFile to ChunkedFile inside chunked input wrappers to stream file content asynchronously in fixed-size chunks rather than loading entire files into memory.
RandomAccessFile raf = new RandomAccessFile(file, "r");long fileLength = raf.length();Http2DataChunkedInput chunkedInput = new Http2DataChunkedInput( new ChunkedFile(raf, 0, fileLength, 8192), stream);ctx.writeAndFlush(chunkedInput, ctx.newProgressivePromise());
Enforce Strict Input Size Bounds and Protocol Parsing Limits
Approximately 897 tokens
Use when
Configuring network protocol decoders, HTTP codecs, and frame decoders to ingest untrusted data safely.
Secure rules
Rule 1: Configure explicit size bounds and header limits on inbound protocol decoders.
Use configuration classes like HttpDecoderConfig with explicit bounds such as setMaxInitialLineLength, setMaxHeaderSize, and setMaxChunkSize, or pass explicit limits into protocol decoders like StompSubframeDecoder, MqttDecoder, and LengthFieldBasedFrameDecoder to reject oversized or malformed payloads before downstream processing.
HttpDecoderConfig config = new HttpDecoderConfig() .setInitialBufferSize(1024) .setMaxInitialLineLength(4096) .setMaxHeaderSize(8192) .setMaxChunkSize(8192);HttpRequestDecoder decoder = new HttpRequestDecoder(config);
Rule 2: Enforce strict header validation, canonicalization, and parsing checks.
Ensure decoders maintain strict validation defaults, such as enabling setValidateHeaders(true), rejecting duplicate content lengths via setAllowDuplicateContentLengths(false), enabling strict line parsing, and restricting UTF-8 string validation to reject malformed sequences, null characters, and injection vectors.
HttpDecoderConfig config = new HttpDecoderConfig() .setValidateHeaders(true) .setAllowDuplicateContentLengths(false) .setStrictLineParsing(true) .setUseRfc9112TransferEncoding(true);
Verify that input buffers contain sufficient readable bytes before parsing frames, handle null return values for truncated packets, check decoder result flags like decoderResult().isFailure() or frame invalidity flags, and catch decoding exceptions to terminate sessions securely.
public class FrameDecoder extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { if (in.readableBytes() < 4) { return; } int length = in.getInt(in.readerIndex()); if (in.readableBytes() < 4 + length) { return; } in.skipBytes(4); out.add(in.readRetainedSlice(length)); }}
Validate and Normalize Request Targets and Paths During Routing and Deep Link Resolution
Use when
Handling inbound HTTP requests, converting protocol headers, or parsing deep link URIs for routing and parameter extraction.
Secure rules
Rule 1: Inspect raw path components or sanitize decoded paths prior to route matching to prevent path ambiguity and traversal bypasses.
When using QueryStringDecoder, remember that decoder.path() automatically decodes percent-encoded characters while decoder.rawPath() preserves the original encoding. Route matching logic should inspect raw paths or explicitly normalize decoded paths, accounting for matrix parameters and boundary tokens.
Rule 2: Strictly validate converted HTTP/2 pseudo-headers before passing target paths to downstream routing components.
When converting HTTP/1.x requests to HTTP/2 headers using HttpConversionUtil.toHttp2Headers, enable header validation and verify that the resulting :path pseudo-header complies with expected origin-form routing constraints to prevent routing mismatches across protocol translation layers.
Safely Manage Reference-Counted OpenSSL Contexts and Engines
Approximately 232 tokens
Use when
Managing the lifecycle of Netty’s ReferenceCountedOpenSslContext and ReferenceCountedOpenSslEngine native resources.
Secure rules
Rule 1: Ensure OpenSSL engines are released before releasing their parent OpenSSL context to prevent native use-after-free access.
Explicitly manage the lifecycle of ReferenceCountedOpenSslEngine instances by invoking release() when they are no longer needed, ensuring all child engines are shut down and released prior to releasing the parent ReferenceCountedOpenSslContext.
Secure Inter-Process and Inter-Component Network Boundaries and Peer Authentication
Approximately 456 tokens
Use when
Developing local inter-process communication (IPC) channels, server sockets, or datagram connections using Netty transports that require strict interface isolation and peer validation.
Secure rules
Rule 1: Explicitly bind local server and datagram channels to loopback addresses rather than wildcard interfaces.
When configuring Netty ServerBootstrap or datagram channels for inter-process communication, avoid wildcard addresses like 0.0.0.0. Bind explicitly to loopback addresses such as 127.0.0.1 or NetUtil.LOCALHOST to prevent exposing internal IPC channels to external network interfaces.
InetSocketAddress localAddress = new InetSocketAddress("127.0.0.1", port);ChannelFuture f = sb.bind(localAddress).sync();
Rule 2: Authenticate local IPC peer processes on Unix domain datagram sockets.
When performing inter-process communication via EpollDomainDatagramChannel over Unix domain sockets, authenticate peer processes by inspecting peer credentials retrieved through peerCredentials() before trusting incoming datagrams.
Rule 3: Enforce QUIC address validation in production network services.
When configuring HTTP/3 or QUIC server endpoints for inter-process or inter-component communication, avoid using InsecureQuicTokenHandler.INSTANCE, which skips address validation tokens and enables UDP amplification attacks. Always configure a validating QuicTokenHandler implementation for production deployments.
Validate HTTP Header Values and Control Characters in Netty Codecs
Approximately 320 tokens
Use when
Use when constructing HTTP/2 headers or translating HTTP/1.x objects to HTTP/2 frames to prevent header injection and control character smuggling.
Secure rules
Rule 1: Enable value validation when constructing HTTP/2 headers from untrusted values
When adding untrusted values to DefaultHttp2Headers, use the three-argument constructor with both header-name and header-value validation enabled. The second boolean enables rejection of prohibited characters such as NUL, CR, LF, DEL, and other control characters.
Http2Headers headers = new DefaultHttp2Headers(true, true, 16);headers.add("x-custom-header", userProvidedValue);
Rule 2: Enable validateHeaders during outbound conversion from HTTP/1.x objects to HTTP/2 frames.
Pass validateHeaders as true when instantiating HttpToHttp2ConnectionHandler so that HttpConversionUtil.toHttp2Headers checks header names, values, and control characters, blocking improper header content from being emitted in outbound traffic.
Configure Connection Idle Timeouts and Certificate Limits to Prevent Resource Exhaustion
Approximately 328 tokens
Use when
Setting up Netty network services, QUIC servers, or SSL contexts where malicious clients could trigger resource exhaustion or memory denial-of-service.
Secure rules
Rule 1: Enforce maximum peer certificate chain size limits on OpenSSL-backed SSL contexts.
When configuring Netty’s OpenSSL-backed SSL context, enforce limits on the maximum accepted peer certificate chain size by setting OpenSslContextOption.MAX_CERTIFICATE_LIST_BYTES on SslContextBuilder to prevent excessive memory allocation during TLS handshakes.
Rule 2: Configure maximum idle timeouts on QUIC server and client builders.
Explicitly configure a maximum idle timeout on QuicServerBuilder and QuicClientBuilder instances using maxIdleTimeout() to ensure abandoned connections are properly cleaned up and do not remain allocated in memory indefinitely.
Rule 2: Bind worker threads explicitly to a designated ThreadGroup using DefaultThreadFactory.
Pass an explicit ThreadGroup parameter when instantiating DefaultThreadFactory to enforce distinct execution boundaries instead of inheriting the caller thread group dynamically.
ThreadGroup isolatedGroup = new ThreadGroup("isolated-workers");DefaultThreadFactory factory = new DefaultThreadFactory( "worker-pool", false, Thread.NORM_PRIORITY, isolatedGroup);Thread worker = factory.newThread(task);
Set the JVM system property -Dio.netty.noUnsafe=true when launching applications in secure environments to prevent dynamic acquisition of sun.misc.Unsafe capabilities.
Rule 4: Restrict native library extraction work directory permissions to a private, secure path.
Configure the io.netty.native.workdir system property to point to a dedicated, process-private directory with restricted filesystem permissions and native execution support.
Sanitize Logging and Telemetry Hints to Prevent Sensitive Data Disclosure
Use when
Configuring network channel logging or resource leak tracking mechanisms that process user payloads or telemetry.
Secure rules
Rule 1: Configure LoggingHandler with ByteBufFormat.SIMPLE to prevent raw payload leakage.
Use ByteBufFormat.SIMPLE when instantiating LoggingHandler in environments processing sensitive network data to ensure only byte sizes rather than full hex dumps of payload contents are written to log files.
LoggingHandler handler = new LoggingHandler(LogLevel.INFO, ByteBufFormat.SIMPLE);channel.pipeline().addLast(handler);
Configure Explicit SSL Session Cache Limits and Timeouts
Approximately 220 tokens
Use when
When instantiating server SSL contexts and setting explicit upper bounds for session cache size and timeouts to prevent unbounded memory consumption from cached TLS sessions.
Secure rules
Rule 1: Set explicit non-zero upper bounds for sessionCacheSize and sessionTimeout on the server SSL session context.
When instantiating server SSL contexts using SslContextBuilder, configure sessionCacheSize and sessionTimeout with explicit values to prevent unbounded memory consumption from cached TLS sessions.