Status: Patched
This vulnerability has been verified as resolved and deployed.
stream accepts revoked client certificates despite ssl_ocsp on (CVE-2026-28755)
Summary
NGINX stream module allows TLS handshake to succeed with revoked client certificates when ssl_ocsp on is configured
When a stream listener is configured with both ssl_verify_client on and ssl_ocsp on, nginx performs the OCSP request and learns that the presented client certificate is revoked, but it still completes the TLS handshake and allows the session to reach application data.
The root cause is a logic gap specific to stream: the OCSP helper records revocation state, but the stream verification path in ngx_stream_ssl_handler() checks only SSL_get_verify_result() and whether a certificate is present. It never calls ngx_ssl_ocsp_get_status(). The HTTP path does enforce the OCSP result — ngx_http_request.c explicitly calls ngx_ssl_ocsp_get_status() and rejects the request when the result is not good. The result is that OCSP executes, revocation is detected, but revocation is ignored in stream.
CVSS Score
Vulnerability Location
Sink-to-Source Analysis
The stream configuration path enables OCSP checks through ngx_ssl_ocsp() when ssl_ocsp on is set.
ngx_ssl_ocsp_validate() performs the OCSP transaction and asynchronous state machine. It correctly receives and parses the revoked OCSP response.
The stream verification path checks only SSL_get_verify_result() and certificate presence. It never calls ngx_ssl_ocsp_get_status(), so revocation state is ignored.
For comparison, the HTTP path does enforce the OCSP result by calling ngx_ssl_ocsp_get_status() and rejecting the request when the result is not good.
Impact Analysis
Critical Impact
This breaks revocation enforcement for stream mTLS services. A revoked client certificate remains usable until the certificate itself expires or the private key becomes unavailable to the attacker. Any internal TCP service fronted by NGINX stream and protected with client certificates can remain reachable after revocation. Deployments that rely on OCSP revocation checks to disable compromised or deprovisioned client certificates are effectively unprotected.
Attack Surface
Any NGINX deployment using the stream module with TLS client authentication (ssl_verify_client on) and OCSP revocation checking (ssl_ocsp on).
Preconditions
The target uses the stream module with TLS client authentication enabled and ssl_ocsp on configured. The attacker still has the private key for a revoked client certificate. NGINX can reach an OCSP responder, either via ssl_ocsp_responder or certificate AIA.
Proof of Concept
Environment Setup
From the nginx source root, build nginx with stream and SSL support:
Target Configuration
The PoC creates a self-contained CA, server cert, client cert, OCSP responder cert, then revokes the client cert and starts an OCSP responder and nginx with this config:
Exploit Delivery
After the CA and OCSP responder are set up and the client cert is revoked:
- Verify OCSP reports the certificate as revoked:
- Connect with the revoked certificate:
- Check nginx debug log:
Outcome
A revoked client certificate is accepted by the stream listener despite OCSP confirming revocation. The TLS handshake completes and application data (stream-ok) is returned to the attacker.
Expected Response:
The OCSP query reports the client certificate as revoked. openssl s_client still completes the handshake and prints stream-ok. The nginx debug log contains both:
This proves nginx both recognized the revocation and still accepted the certificate in stream.
