CVE-2026-56821

HIGHPre-NVD 7.47.4
EchelonGraph scoreLOW confidence

This high-severity CVE scores 7.4 under the CNA's CVSS (NVD's own analysis pending). EPSS exploit-prediction score not yet available (the EPSS model rescores nightly; freshly-published CVEs typically appear within 48 hours). GitHub Security Advisory data not yet ingested — confidence will rise once GHSA publishes (typical lag: hours to days for open-source ecosystem CVEs; never for infrastructure-only CVEs).

Triggered by: NVD CVSS baseline
Sources: cna:github_m
7.4
EchelonGraph verdictPlan a fixSerious severity, but no confirmed exploitation yet.
  • High severity, but no confirmed exploitation yet
CISA-KEV: Not listedEPSS: CVSS: 7.4Exploit: NoneExposed: 0

No vendor fix yet — apply a workaround or compensating control (WAF / firewall / segmentation) and watch for a patch.

Netty: Out-of-date OCSP Responses Accepted by OcspServerCertificateValidator

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:

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;
  • 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

@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() { @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 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() { @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.

CVSS v3
7.4
EG Score
7.4(low)
EG Risk
38(Track)
EG Risk 38/100SSVC: Track

EG Risk is EchelonGraph's 0–100 priority score: it fuses intrinsic severity with real-world exploitation and automatability so you can rank equal-severity CVEs and fix the most dangerous first. Higher = act sooner. Distinct from the 0–10 EG Score (severity).

How it’s computed
Severity74% × 45%
Exploitation0% × 40%
Automatability30% × 15%
Action: Routine — remediate on your standard cadence.
EPSS
KEV
Not listed

Published

July 22, 2026

Last Modified

July 22, 2026

Vendor Advisories for CVE-2026-56821(1)

These vendors published their own advisory mentioning this CVE — often with vendor-specific remediation steps + affected product lists not in NVD.

Affected Packages

(1 across 1 ecosystem)
Maven(1)
PackageVulnerable rangeFixed inDependents
io.netty:netty-handler-ssl-ocsp4.1.100.Final ... 4.1.99.Final (50 versions)4.1.136.Final

Data Freshness Timeline

(refreshed 2× in last 7d / 2× in last 30d)

Each row is a source pipeline that fetched or updated this CVE on that date, with what changed. For example, "NVD update" means NVD published or revised its analysis for this CVE; "MITRE cvelistV5" means we ingested or refreshed it from the CNA feed. Most recent first.

  1. 2026-07-23 03:20 UTCEG score recompute
  2. 2026-07-22 22:27 UTCEG score recompute

Frequently asked(4)

What is CVE-2026-56821?
CVE-2026-56821 is a high vulnerability published on July 22, 2026. Netty: Out-of-date OCSP Responses Accepted by OcspServerCertificateValidator 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…
When was CVE-2026-56821 disclosed?
CVE-2026-56821 was first published in the National Vulnerability Database on July 22, 2026. EchelonGraph re-ingests CVE updates from NVD on a 2-hour cycle, so this page reflects the latest published state.
What is the CVSS score of CVE-2026-56821?
CVE-2026-56821 has a CVSS v4.0 base score of 7.4 (CNA self-assessment; NVD's own analysis pending). The EG score is currently aggregating — additional source signals are being incorporated as they become available..
How do I remediate CVE-2026-56821?
Patch to the fixed version published by the affected vendor. Where vendor advisories exist for CVE-2026-56821, EchelonGraph cross-links them in the Vendor Advisories panel below — those typically contain the canonical remediation steps, fixed version numbers, and any vendor-specific mitigations.

Dependency Blast Radius

See which npm, PyPI, Go, and Maven packages are affected by CVE-2026-56821

Explore →

Is Your Infrastructure Affected by CVE-2026-56821?

EchelonGraph automatically scans your cloud infrastructure and maps CVE exposure using blast radius analysis.