CVE-2026-56820: Netty: Missing CertificateID Validation in OCSP Response Allows Replay Attacks
Summary Netty's OcspClient does not validate that the CertificateID in an OCSP response matches the requested CertificateID. A bad actor can replay a GOOD status response issued for an unrelated certificate (by the same CA) to bypass revocation checks for any certificate.
Details io.netty.handler.ssl.ocsp.OcspClient#validateResponse fails to assert that the CertificateID within the returned BasicOCSPResp matches the original certificate being validated.
When OcspClient.query(...) executes, it builds an OCSP request using the victim certificate's serial number and issuer hash. It then sends this request and receives a response. While the client verifies the signature of the response against the trusted issuer (or a valid responder chain), it never checks the CertificateID inside the response payload.
A bad actor who has access to any other valid, non-revoked certificate issued by the same CA can obtain a legitimately signed OCSP response indicating that the unrelated certificate is GOOD. The bad actor can then return this valid response to the Netty client when it queries the status of any other certificate (e.g., a revoked certificate) issued by the same CA. Because the signature is valid (signed by the CA) and the CertificateID is ignored, the client will incorrectly accept the target certificate as valid.
As per https://datatracker.ietf.org/doc/html/rfc6960#section-3.2 we have:
Prior to accepting a signed response for a particular certificate as valid, OCSP clients SHALL confirm that:
1. The certificate identified in a received response corresponds to the certificate that was identified in the corresponding request;
PoC The following test case in io.netty.handler.ssl.ocsp.OcspClientTest demonstrates how the implementation accepts a forged OCSP response for a completely unrelated certificate, proving the bypass.
java @Test void testCertIdBypass() throws Exception { 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.idadocsp, 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);
X509CertificateHolder caHolder = new JcaX509CertificateHolder(caRoot.getCertificate()); BasicOCSPResp forgedBasicResp = createBasicOcspResponse(caRoot, new X509CertificateHolder[]{caHolder}); OCSPResp forgedResponse = new OCSPRespBuilder().build(OCSPRespBuilder.SUCCESSFUL, forgedBasicResp); byte[] forgedResponseEncoded = forgedResponse.getEncoded();
EventLoopGroup group = new MultiThreadIoEventLoopGroup(1, NioIoHandler.newFactory()); try { IoTransport transport = 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().execute(() -> { ctx.pipeline().fireChannelActive();
DefaultFullHttpResponse httpResponse = new DefaultFullHttpResponse( HttpVersion.HTTP11, HttpResponseStatus.OK, Unpooled.wrappedBuffer(forgedResponseEncoded)); httpResponse.headers().set(HttpHeaderNames.CONTENTTYPE, "application/ocsp-response"); httpResponse.headers().set(HttpHeaderNames.CONTENTLENGTH, httpResponse.content().readableBytes());
ctx.pipeline().fireChannelRead(httpResponse); }); } }); return channel; }, NioDatagramChannel::new);
DnsNameResolver resolver = OcspServerCertificateValidator.createDefaultResolver(transport); Promise<BasicOCSPResp> promise = OcspClient.query(targetCert.getCertificate(), caRoot.getCertificate(), false, transport, resolver);
promise.await();
assertFalse(promise.isSuccess(), "Netty incorrectly accepted the response for the unrelated certificate. The CertificateID was ignored!"); } finally { group.shutdownGracefully(); } }
Impact Certificate Validation Bypass. Any application using Netty's OcspClient to check certificate revocation status is impacted.
Other sources
Netty is a network application framework for development of protocol servers and clients. In versions 4.2.0.Final through 4.2.15.Final and prior to 4.1.135.Final, OcspClient does not validate that the CertificateID in an OCSP response matches the requested CertificateID, which can lead to replay attack. OcspClient.validateResponse accepts a legitimately signed GOOD status response for an unrelated certificate issued by the same CA, allowing bypass of revocation checks for another certificate. This issue is fixed in versions 4.1.136.Final and 4.2.16.Final.
— MITRE
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
maven/io.netty:netty-handler-ssl-ocspto a version that resolves this vulnerability.Fixed in 4.1.136.Final - Upgrade
Upgrade
maven/io.netty:netty-handler-ssl-ocspto a version that resolves this vulnerability.Fixed in 4.2.16.Final - Upgrade
Upgrade
io.netty.handler.ssl.ocsp.OcspClientto a version that resolves this vulnerability.Fixed in 4.1.136.Final - Upgrade
Upgrade
io.netty.handler.ssl.ocsp.OcspClientto a version that resolves this vulnerability.Fixed in 4.2.16.Final - Operational
If you rely on Netty's OcspClient for certificate revocation checking, review and remediate any systems that may have accepted replayed OCSP responses between versions 4.2.0.Final through 4.2.15.Final and prior to 4.1.135.Final; ensure the affected Netty components are upgraded to 4.1.136.Final or 4.2.16.Final.
Event History
Frequently Asked Questions
What is the severity of CVE-2026-56820?
CVE-2026-56820 has a severity rating of high with a score of 7.4.
How do I fix CVE-2026-56820?
To fix CVE-2026-56820, upgrade to a version of Netty that is higher than 4.2.15.Final or 4.1.135.Final.
What type of attack is possible due to CVE-2026-56820?
CVE-2026-56820 allows for replay attacks due to missing validation of the CertificateID in OCSP responses.
Which versions of Netty are affected by CVE-2026-56820?
Versions of Netty from 4.2.0.Final through 4.2.15.Final and prior to 4.1.135.Final are affected by CVE-2026-56820.
Why is it important to address CVE-2026-56820?
It is important to address CVE-2026-56820 to prevent potential security breaches related to OCSP response validation.