Skip to main content

Netty CVE-2026-56821

HIGH
Improper Check for Certificate Revocation (CWE-299)
2026-07-22 https://github.com/netty/netty GHSA-g7hg-vrcf-mvmr
7.4
CVSS 3.1 · Vendor: https://github.com/netty/netty
Share

Severity by source

Vendor (https://github.com/netty/netty) PRIMARY
7.4 HIGH
AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N
vuln.today AI
7.4 HIGH

Network-reachable and unauthenticated (AV:N/PR:N) but AC:H because the attacker needs on-path position plus a revoked cert and a pre-captured signed GOOD response; bypassing TLS auth yields C:H/I:H, A:N (NPE DoS scored separately).

3.1 AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N
4.0 AV:N/AC:H/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N
SUSE
HIGH
qualitative
Red Hat
5.7 MEDIUM
qualitative

Primary rating from Vendor (https://github.com/netty/netty).

CVSS VectorVendor: https://github.com/netty/netty

Attack Vector
Network
Attack Complexity
High
Privileges Required
None
User Interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
None

Lifecycle Timeline

3
Source Code Evidence Fetched
Jul 22, 2026 - 22:21 vuln.today
Analysis Generated
Jul 22, 2026 - 22:21 vuln.today
CVE Published
Jul 22, 2026 - 21:46 github-advisory
HIGH 7.4

Blast Radius

ecosystem impact
† from your stack dependencies † transitive graph · vuln.today resolves 4-path depth
  • 74 maven packages depend on io.netty:netty-handler-ssl-ocsp (2 direct, 72 indirect)

Ecosystem-wide dependent count for version 4.2.0.Final.

DescriptionCVE.org

Summary

OcspServerCertificateValidator flags an out-of-date OCSP response but does not stop processing it, so an expired GOOD response is still reported as VALID, letting an on-path attacker replay a stale GOOD response to bypass revocation of a since-revoked certificate.

Details

In io.netty.handler.ssl.ocsp.OcspServerCertificateValidator#userEventTriggered the freshness check has no return, so execution falls through and a VALID OcspValidationEvent is still fired:

java
                        if (!(current.after(response.getThisUpdate()) &&
                                current.before(response.getNextUpdate()))) {
                            ctx.fireExceptionCaught(new IllegalStateException("OCSP Response is out-of-date"));
                        }

Nonce validation is optional and off by default, so freshness is the only replay defense - and it is not enforced. Additionally getNextUpdate() may be null, making current.before(null) throw NullPointerException.

https://datatracker.ietf.org/doc/html/rfc6960#section-3.2

   5. The time at which the status being indicated is known to be
      correct (thisUpdate) is sufficiently recent;

   6. When available, the time at or before which newer information will
      be available about the status of the certificate (nextUpdate) is
      greater than the current time.

PoC

Add the test below to io.netty.handler.ssl.ocsp.OcspServerCertificateValidatorTest

java
    @Test
    void staleOcspResponseIsRejected() 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.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);

        Date past = new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7));
        CertificateID certId = new CertificateID(
                new JcaDigestCalculatorProviderBuilder().build().get(CertificateID.HASH_SHA1),
                new JcaX509CertificateHolder(caRoot.getCertificate()),
                targetCert.getCertificate().getSerialNumber());
        BasicOCSPRespBuilder respBuilder = new BasicOCSPRespBuilder(
                new RespID(new JcaX509CertificateHolder(caRoot.getCertificate()).getSubject()));
        respBuilder.addResponse(certId, CertificateStatus.GOOD, past, past);
        BasicOCSPResp expiredBasicResp = respBuilder.build(
                new JcaContentSignerBuilder("SHA256withRSA").build(caRoot.getKeyPair().getPrivate()),
                new X509CertificateHolder[0],
                past);
        final byte[] responseEncoded = new OCSPRespBuilder()
                .build(OCSPRespBuilder.SUCCESSFUL, expiredBasicResp).getEncoded();

        IoTransport defaultTransport = createDefaultTransport();
        IoTransport mockTransport = IoTransport.create(defaultTransport.eventLoop(), () -> {
                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.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);
                        });
                    }
                });
                return channel;
            }, defaultTransport.datagramChannel());

            SslContext serverSslCtx = SslContextBuilder
                    .forServer(targetCert.getKeyPair().getPrivate(),
                            targetCert.getCertificate(), caRoot.getCertificate())
                    .build();
            Channel serverChannel = new ServerBootstrap()
                    .group(defaultTransport.eventLoop())
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ch.pipeline().addLast(serverSslCtx.newHandler(ch.alloc()));
                        }
                    })
                    .bind(0).sync().channel();

            int serverPort = ((InetSocketAddress) serverChannel.localAddress()).getPort();

            AtomicBoolean validEventFired = new AtomicBoolean();
            AtomicReference<Throwable> caughtException = new AtomicReference<>();
            CountDownLatch latch = new CountDownLatch(1);

            DnsNameResolver resolver = OcspServerCertificateValidator.createDefaultResolver(mockTransport);
            SslContext clientSslCtx = SslContextBuilder.forClient()
                    .trustManager(InsecureTrustManagerFactory.INSTANCE)
                    .build();
            new Bootstrap()
                    .group(defaultTransport.eventLoop())
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ch.pipeline().addLast(clientSslCtx.newHandler(ch.alloc(), "127.0.0.1", serverPort));
                            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 OcspValidationEvent &&
                                            ((OcspValidationEvent) evt).response().status() ==
                                                    OcspResponse.Status.VALID) {
                                        validEventFired.set(true);
                                    }
                                    ctx.fireUserEventTriggered(evt);
                                }

                                @Override
                                public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
                                    caughtException.compareAndSet(null, cause);
                                    ctx.channel().close();
                                    latch.countDown();
                                }
                            });
                        }
                    })
                    .connect("127.0.0.1", serverPort).sync();

            assertTrue(latch.await(5, TimeUnit.SECONDS));
            assertFalse(validEventFired.get(),
                    "OcspValidationEvent(VALID) must not be emitted for a stale OCSP response");
            assertNotNull(caughtException.get());
            assertInstanceOf(IllegalStateException.class, caughtException.get());

            serverChannel.close().sync();
            resolver.close();
    }

Impact

Certificate revocation bypass via replay of an expired OCSP response. Any application using OcspServerCertificateValidator is affected; a revoked certificate can be accepted.

AnalysisAI

Certificate revocation bypass in the Netty netty-handler-ssl-ocsp module (versions before 4.1.136.Final, and 4.2.0.Final through 4.2.15.Final) lets an on-path attacker replay a stale, expired-but-GOOD OCSP response to make OcspServerCertificateValidator accept a certificate that has since been revoked. A missing return statement after the freshness check causes execution to fall through and still fire a VALID OcspValidationEvent even after flagging the response as out-of-date. Publicly available exploit code exists (a PoC unit test is embedded in the GHSA advisory); the issue is not listed in CISA KEV and no EPSS score was provided.

Technical ContextAI

The flaw lives in io.netty.handler.ssl.ocsp.OcspServerCertificateValidator#userEventTriggered, part of Netty's optional OCSP (Online Certificate Status Protocol, RFC 6960) stapling/validation support built on Bouncy Castle. Per RFC 6960 section 3.2, a client must confirm both that thisUpdate is sufficiently recent and that nextUpdate is greater than the current time before trusting a status. The code performs this check - if the current time is not within the thisUpdate/nextUpdate window it raises IllegalStateException('OCSP Response is out-of-date') via fireExceptionCaught - but omits a return, so the method continues and still emits a VALID event. Because nonce validation is optional and disabled by default, temporal freshness is the only defense against replay, and it is not enforced. This maps to CWE-299 (Improper Check for Certificate Revocation). A secondary defect exists: getNextUpdate() may return null, causing current.before(null) to throw NullPointerException, a potential crash/DoS path.

RemediationAI

Vendor-released patch: upgrade to 4.1.136.Final (for 4.1.x deployments) or 4.2.16.Final (for 4.2.x deployments), per the release notes at https://github.com/netty/netty/releases/tag/netty-4.1.136.Final and https://github.com/netty/netty/releases/tag/netty-4.2.16.Final and the advisory at https://github.com/netty/netty/security/advisories/GHSA-g7hg-vrcf-mvmr. If you cannot upgrade immediately, enable OCSP nonce validation where your deployment supports it so that replayed responses are rejected on nonce mismatch rather than relying solely on freshness (trade-off: requires OCSP responders that echo nonces, and not all responders do). As a stronger compensating control, do not depend on OcspServerCertificateValidator as the sole revocation mechanism - pair it with short-lived certificates or an independent CRL/OCSP check outside the vulnerable code path - and shorten certificate lifetimes to reduce the window in which a revoked-but-cached GOOD response remains replayable. Upgrading is strongly preferred, as the workarounds only narrow rather than close the gap.

More in Java

View all
CVE-2012-4681 CRITICAL POC
9.8 Aug 28

Oracle Java SE 7 Update 6 and earlier contains multiple sandbox bypass vulnerabilities via the ClassFinder and forName m

CVE-2015-7450 CRITICAL POC
9.8 Jan 02

Remote code execution in IBM Sterling B2B Integrator, Sterling Integrator, and Tivoli Common Reporting allows unauthenti

CVE-2013-2465 CRITICAL POC
9.8 Jun 18

Java Runtime Environment sandbox bypass via incorrect image channel verification in 2D component allows remote unauthent

CVE-2011-3544 CRITICAL POC
9.8 Oct 19

Oracle Java SE JDK/JRE 7 and 6 Update 27 and earlier allows remote code execution with complete system compromise throug

CVE-2010-1871 HIGH POC
8.8 Aug 05

JBoss Seam 2 in Red Hat JBoss EAP 4.3.0 fails to sanitize JBoss Expression Language inputs, allowing remote attackers to

CVE-2012-1723 CRITICAL POC
9.8 Jun 16

Unspecified vulnerability in the Java Runtime Environment (JRE) component in Oracle Java SE 7 update 4 and earlier, 6 up

CVE-2013-0422 CRITICAL POC
9.8 Jan 10

Multiple vulnerabilities in Oracle Java 7 before Update 11 allow remote attackers to execute arbitrary code by (1) using

CVE-2012-0507 CRITICAL POC
9.8 Jun 07

Unspecified vulnerability in the Java Runtime Environment (JRE) component in Oracle Java SE 7 Update 2 and earlier, 6 Up

CVE-2015-4852 CRITICAL POC
9.8 Nov 18

The WLS Security component in Oracle WebLogic Server 10.3.6.0, 12.1.2.0, 12.1.3.0, and 12.2.1.0 allows remote attackers

CVE-2012-5076 CRITICAL POC
9.8 Oct 16

Unspecified vulnerability in the Java Runtime Environment (JRE) component in Oracle Java SE 7 Update 7 and earlier allow

CVE-2017-3066 CRITICAL POC
9.8 Apr 27

Remote unauthenticated attackers can execute arbitrary code on Adobe ColdFusion servers through Java deserialization fla

CVE-2012-0391 CRITICAL POC
9.8 Jan 08

The ExceptionDelegator component in Apache Struts before 2.2.3.1 interprets parameter values as OGNL expressions during

Vendor StatusVendor

SUSE

Severity: Important
Product Status
SUSE Linux Enterprise Desktop 15 SP7 Not-Affected
SUSE Linux Enterprise Desktop 15 SP7 Not-Affected
SUSE Linux Enterprise High Performance Computing 15 SP7 Not-Affected
SUSE Linux Enterprise High Performance Computing 15 SP7 Not-Affected
SUSE Linux Enterprise Module for Development Tools 15 SP7 Not-Affected

Share

CVE-2026-56821 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy