“OCSP stapling not offered” means the HTTPS server does not attach a signed OCSP revocation response to its TLS handshake, so clients must query the certificate authority themselves or skip the check. Fix it by enabling stapling (nginx: ssl_stapling on; Apache: SSLUseStapling On plus SSLStaplingCache), provided the certificate actually contains an OCSP URL.
What the scanner is actually detecting
This finding comes from testssl.sh. It is a hardening check in the server defaults section (-S), not a vulnerability plugin in Nessus or OpenVAS. testssl.sh connects with openssl s_client -status, which sends the TLS “certificate status request” extension, and looks at what comes back. If OpenSSL prints OCSP response: no response sent, the report shows:
OCSP URI http://ocsp.example-ca.com
OCSP stapling not offered
The severity depends on the certificate. In testssl.sh 3.2 the JSON entry OCSP_stapling is rated LOW when the certificate contains an OCSP responder URL (stapling was possible but is not configured) and INFO when it does not (stapling is impossible). Two related lines are worth reading at the same time:
- OCSP must staple extension: requires OCSP stapling (NOT ok), rated HIGH. The certificate carries the TLS Feature (Must-Staple) extension but the server does not staple, so clients that enforce it can refuse the connection.
- NOT ok — neither CRL nor OCSP URI provided, rated HIGH. The certificate offers no revocation mechanism at all, which is a certificate issue, not a server setting.
Real-world risk
Missing stapling is not exploitable on its own. Nothing leaks and no attacker gains access because of it. The cost is indirect:
- Privacy. A client that checks revocation without a staple contacts the CA’s OCSP responder, which tells the CA which site is being visited. Both the Apache documentation and Let’s Encrypt cite this as the main drawback of plain OCSP.
- Latency and reliability. That extra lookup depends on a third-party server. Stapling lets the web server fetch one signed response and reuse it for every client while it is valid.
- Limited protection either way. Most OCSP clients fail open when they get no answer. An attacker holding a stolen, revoked certificate simply will not staple, so stapling does not stop that attack unless the certificate is Must-Staple.
The industry is also moving away from OCSP. In August 2023 the CA/Browser Forum made OCSP optional for publicly trusted CAs, and Let’s Encrypt removed OCSP URLs from its certificates on May 7, 2025 and shut down its responders on August 6, 2025. Treat this as a low-priority hardening item that is worth enabling where your CA still runs OCSP.
How to confirm it on the host
First check whether the certificate even has an OCSP URL. Empty output means stapling cannot work with this certificate:
openssl s_client -connect www.example.com:443 -servername www.example.com </dev/null 2>/dev/null
| openssl x509 -noout -ocsp_uri
Then request a staple, the same way testssl.sh does:
openssl s_client -connect www.example.com:443 -servername www.example.com -status </dev/null 2>/dev/null
| grep -A 12 "OCSP response"
OCSP response: no response sent confirms the finding. Always pass -servername so you test the same virtual host and certificate the scanner saw. Finally, look at the configuration:
sudo nginx -T 2>/dev/null | grep -Ei "ssl_stapling|ssl_trusted_certificate|resolver"
sudo grep -RiE "SSLUseStapling|SSLStaplingCache" /etc/apache2/ /etc/httpd/ 2>/dev/null
How to fix it
Three things must be true on any platform: the certificate has an OCSP URL, the server knows the issuer (intermediate) certificate, and the server can resolve and reach the OCSP responder over HTTP. Outbound firewall rules from web servers often block that last part.
nginx
Add the directives to the server block that terminates TLS (they are also valid at http level):
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate /etc/nginx/ssl/www.example.com.fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/www.example.com.key;
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/nginx/ssl/ca-chain.pem; # intermediates + root, PEM
resolver 192.0.2.53 valid=300s; # a DNS server nginx can reach
}
Per the nginx documentation, the issuer certificate must be known: if ssl_certificate does not contain the intermediates, put the issuer in ssl_trusted_certificate. For ssl_stapling_verify, that file must hold the issuer, the root and all intermediates. The resolver directive is needed to look up the responder’s hostname; nginx recommends a DNS server on a trusted local network. Apply and check the log:
sudo nginx -t && sudo systemctl reload nginx
sudo grep '"ssl_stapling" ignored' /var/log/nginx/error.log
A warning of “ssl_stapling” ignored, no OCSP responder URL in the certificate means the certificate cannot be stapled. issuer certificate not found means the chain is incomplete.
Apache httpd 2.4 (mod_ssl)
The Apache SSL how-to places both directives at global scope, outside any <VirtualHost>, next to the other global SSL settings (for example /etc/apache2/mods-enabled/ssl.conf on Debian and Ubuntu). SSLStaplingCache is only valid in server config context, and a cache is mandatory:
SSLUseStapling On
SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"
Use the same directory as your existing SSLSessionCache line (relative paths resolve against ServerRoot). The shmcb type needs mod_socache_shmcb. Check with apachectl -M | grep socache, and on Debian or Ubuntu enable it with sudo a2enmod socache_shmcb if it is missing. The documentation also recommends these production values, since the defaults pass responder errors to clients and cache good responses for only an hour:
SSLStaplingReturnResponderErrors off
SSLStaplingResponderTimeout 4
SSLStaplingStandardCacheTimeout 172800
SSLStaplingErrorCacheTimeout 60
The certificate chain must be configured through SSLCertificateFile or SSLCertificateChainFile. Otherwise Apache logs AH02217: ssl_stapling_init_cert: Can’t retrieve issuer certificate! and does not staple. If the certificate has no OCSP URL but your CA runs a responder, set SSLStaplingForceURL in that virtual host. Apply the change:
sudo apachectl configtest && sudo systemctl reload apache2 # httpd on RHEL-family systems
Load balancers, CDNs and appliances
Stapling happens wherever TLS terminates. If a load balancer, reverse proxy or CDN presents the certificate, configure stapling there using that vendor’s documentation. Changing the origin server will not affect what the scanner sees.
How to verify the fix and rescan
Run the -status test again. A working staple shows OCSP Response Status: successful (0x0) followed by a Cert Status line reading good. nginx fetches the response on demand in each worker process, so the first handshake or two after a reload can still say no response sent. Repeat the command a few times before you conclude it failed. Then rerun the scanner check:
./testssl.sh -S www.example.com
The OCSP stapling line should now read offered, and OCSP must staple extension should read supported if your certificate uses it.
What can break and how to roll back
- Nothing breaks when the responder is unreachable, with one exception. A server that cannot fetch a response usually just stops stapling. Must-Staple certificates are the exception: clients that enforce the extension can reject the connection.
- Apache defaults can staple an error. With SSLStaplingReturnResponderErrors and SSLStaplingFakeTryLater both on (the defaults), a failed query produces a synthesized “tryLater” response. testssl.sh then shows a warning about an error response from the OCSP responder instead of “offered”.
- Configuration errors. Putting SSLStaplingCache inside a virtual host, or leaving out the cache module, stops Apache from starting. Always run configtest before reloading.
- Cache size. With many certificates, the 32768-byte example cache can fill up. Apache logs AH01929 when it cannot store a response; increase the size.
Rollback is immediate. Set ssl_stapling off; or SSLUseStapling Off (per virtual host if needed) and reload. Unlike HSTS, clients cache no policy, but a Must-Staple extension lives in the certificate and can only be removed by reissuing it.
Common false positive reasons
- No OCSP URL in the certificate. This applies to every Let’s Encrypt certificate issued since May 7, 2025 and to many internal CAs. testssl.sh rates it INFO, and no server setting can change it. Record it as not applicable.
- Test ran right after a reload. nginx had not fetched a response yet.
- Wrong virtual host. A scan by IP address without SNI hits the default server block, which may use a different certificate or configuration.
- Wrong layer. Stapling is configured on the origin, but TLS terminates on a proxy, or the reverse.
- Egress blocked. The configuration is correct, but the server cannot resolve or reach the responder. This is a real finding with a network cause, so check the error log.
FAQ
Is “OCSP stapling not offered” a vulnerability?
No. It is a hardening and privacy item. testssl.sh rates it LOW at most, and INFO when the certificate has no OCSP URL.
My certificate is from Let’s Encrypt. How do I fix this?
You cannot, and you do not need to. Let’s Encrypt certificates no longer contain OCSP URLs, and its responders were shut down on August 6, 2025. Mark the finding not applicable.
Does the web server need internet access for stapling?
It needs DNS resolution and outbound HTTP to the CA’s OCSP responder, which is usually on port 80. Without that, it cannot fetch responses.
Should I enable ssl_stapling_verify in nginx?
Yes. It checks responses before stapling them, but it requires the full issuer chain and root in ssl_trusted_certificate.
Tracking this finding across many hosts
Whether stapling is fixable depends on each certificate’s issuer, so it helps to track this finding next to a TLS certificate inventory rather than as isolated tickets. If the TLS scanner you use is one of the 16 whose findings SITEY, a self-hosted vulnerability management platform, can import, its AI triage can suggest likely false positives (such as certificates with no OCSP URL) with evidence, while a person makes the final decision. Duplicates are merged per scanner, not across scanners, so the same host reported by two tools stays as two records.