CVE-2026-93493: Netty: netty-handler-ssl-ocsp: io.netty/netty-handler-ssl-ocsp: netty: ocsp validation silently skipped when a response omits the optional nextupdate field

Published Sep 18, 2026
·
Updated

A flaw was found in Netty's netty-handler-ssl-ocsp component. A remote attacker can exploit this vulnerability by providing an Online Certificate Status Protocol (OCSP) response that omits the optional nextUpdate field. This omission causes the OCSP validation to be silently skipped, leading to applications proceeding with an unvalidated certificate. This can result in a bypass of security controls where certificate validation is expected.

Other sources

OCSP Validation Silently Skipped When a Response Omits the Optional nextUpdate Field

A public GitHub Security Advisory (GHSA-jj3c-mwvr-9g52) describes the following issue:

Summary

OcspServerCertificateValidator bounds the age of an OCSP response only when that response carries a nextUpdate field. nextUpdate is optional in RFC 6960. When a responder omits it, the age check passes for a response of any age, the certificate status is computed, and construction of the result object then throws a NullPointerException because OcspResponse requires a non-null nextUpdate.

That throwable is raised inside a promise listener. It never reaches exceptionCaught, so nothing closes the connection, while the listener's finally block still removes the validator from the pipeline. The application therefore receives no OcspValidationEvent and no exception at all - revocation status is never determined, and nothing indicates that validation did not happen.

The trigger is one optional field in a response supplied by a remote party.

Details

The age check, in userEventTriggered:

java Date current = new Date(); Date thisUpdate = response.getThisUpdate(); Date nextUpdate = response.getNextUpdate(); if (thisUpdate == null || !current.after(thisUpdate) || (nextUpdate != null && !current.before(nextUpdate))) { // upper bound is conditional ctx.fireExceptionCaught(new IllegalStateException("OCSP Response is out-of-date")); return; }

With nextUpdate absent the third clause is skipped entirely, so a response whose thisUpdate is arbitrarily far in the past is treated as current. Execution continues to:

java ctx.fireUserEventTriggered(new OcspValidationEvent( new OcspResponse(status, response.getThisUpdate(), response.getNextUpdate())));

and OcspResponse's constructor rejects the null:

java public OcspResponse(Status status, Date thisUpdate, Date nextUpdate) { this.status = checkNotNull(status, "Status"); this.thisUpdate = checkNotNull(thisUpdate, "ThisUpdate"); this.nextUpdate = checkNotNull(nextUpdate, "NextUpdate"); // throws }

Two consequences follow from where that throw happens. It is inside a GenericFutureListener, so it is reported to netty's promise machinery rather than travelling down the pipeline - exceptionCaught is not invoked and the connection stays open. And the enclosing finally still runs, forwarding the original SslHandshakeCompletionEvent and calling ctx.pipeline().remove(this), so the validator takes itself out of the pipeline having produced no verdict.

The closeAndThrowIfNotValid protection, which defaults to true, sits after the point where the exception is thrown and never executes.

Proof of concept

PocOcspReplay.java builds a throwaway CA and a leaf whose Authority Information Access extension points at a local responder, runs a real TLS handshake between two netty channels with new OcspServerCertificateValidator() on the client, and serves three OCSP responses that differ only in their two date fields. Build and run with the attached pom.xml:

docker run --rm -e MAVENOPTS="-Djava.security.egd=file:/dev/./urandom" \ -v "$PWD:/work" -w /work maven:3-eclipse-temurin-21 mvn -B compile exec:java

Observed output:

CONTROL-FRESH thisUpdate=-1h nextUpdate=+24h validator outcome : OcspValidationEvent status=VALID app got a verdict : yes (OcspValidationEvent)

CONTROL-EXPIRED thisUpdate=-400d nextUpdate=-399d validator outcome : IllegalStateException: OCSP Response is out-of-date app got a verdict : yes (exception)

ATTACK thisUpdate=-400d nextUpdate=ABSENT validator outcome : NOTHING - no OcspValidationEvent and no exception app got a verdict : NO - silent connection left open : true validator still in pipeline : false

The two controls carry the argument. CONTROL-FRESH shows the whole path works end to end and yields a VALID verdict. CONTROL-EXPIRED shows that a 400-day-old response is correctly recognised as stale and produces a clean, observable rejection. The attack case uses the same 400-day-old response with nextUpdate removed, and the application is told nothing at all.

Impact

An application using this validator cannot distinguish "the certificate was checked and is good" from "the check never completed", because the successful case and the silent-failure case both leave it with no exception and the validator gone from the pipeline. The only difference is the presence of an OcspValidationEvent, and an application that treats the absence of an event as "nothing to do" proceeds with an unvalidated certificate.

Reaching this requires a response that omits nextUpdate. That is available to a hostile or misconfigured responder, and to an attacker able to answer the OCSP fetch - which travels over plaintext HTTP to the URL in the certificate's AIA extension, with OcspHttpHandler checking only the HTTP status and Content-Type. Note also that the default constructor disables nonce validation (new OcspServerCertificateValidator() delegates to this(false)), so a captured genuine response can be replayed; stripping nextUpdate from it is not required to be signed differently, because omitting the field is a matter of which response the attacker chooses to serve.

The proof of concept also records whether the application wrote data. It did so in all three cases, including both controls, because SslHandshakeCompletionEvent necessarily precedes the asynchronous OCSP query. That is not a differential result and we are not presenting it as one - but it does establish which signal matters. Since the handshake event always arrives first and always reports success, the OcspValidationEvent (or the exception) is the only signal by which an application can learn the revocation outcome. That is exactly the signal this defect suppresses.

On severity, the closest yardstick is this project's own. CVE-2026-56821, "Out-of-date OCSP Responses Accepted b

[truncated]

Affected: - maven:io.netty:netty-handler-ssl-ocsp affected >= 4.2.0.Final, <=4.2.17.Final; fixed unknown - maven:io.netty:netty-handler-ssl-ocsp affected <= 4.1.137.Final; fixed unknown

Fixed versions: see advisory

Advisory: https://github.com/netty/netty/security/advisories/GHSA-jj3c-mwvr-9g52

Red Hat

Affected Software

1 affected component
maven/io.netty/netty-handler-ssl-ocsp>=4.2.0.Final<=4.2.17.Final, =4.1.137.Final

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade maven:io.netty:netty-handler-ssl-ocsp to a version that resolves this vulnerability.

    Patch GHSA-jj3c-mwvr-9g52

Event History

Sep 18, 2026
Data Sourced
via Red Hat·07:22 AM
DescriptionSeverityAffected Software
CVE Published
via MITRE·08:01 AM
Data Sourced
via MITRE·08:01 AM
DescriptionWeakness

Frequently Asked Questions

1

What does an attacker need to trigger the issue?

The attacker needs to provide an OCSP response that omits the optional nextUpdate field. The issue is relevant where an application relies on netty-handler-ssl-ocsp and expects OCSP-based certificate validation to enforce a security control.

2

Is an OCSP response without nextUpdate malformed?

No. The nextUpdate field is optional under RFC 6960, so an OCSP responder can legitimately omit it.

3

What happens to the connection when this condition is triggered?

Construction of the validation result throws a NullPointerException inside a promise listener. According to the advisory description, the exception does not reach exceptionCaught, so the connection is not closed.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203