CVE-2026-7009: OCSP stapling bypass with Apple SecTrust
Medium
Vulnerability Details
## Summary
When curl is built with `--with-apple-sectrust` (or `-DUSE_APPLE_SECTRUST=ON`) and OpenSSL, the `--cert-status` / `CURLOPT_SSL_VERIFYSTATUS` option is silently bypassed when Apple SecTrust handles certificate chain verification instead of OpenSSL.
The user explicitly requests OCSP stapling enforcement, but the connection succeeds even when the server provides no OCSP staple — violating the documented guarantee that curl "aborts the connection" when no OCSP response is received.
## Root Cause
In `lib/vtls/openssl.c`, `Curl_ossl_check_peer_cert()`, commit `b4630ed8fa` (2025-10-31, fixing #19307) introduced a `sectrust_verified` flag that skips OpenSSL's `verifystatus()` call when Apple SecTrust verified the certificate chain:
```c
#ifdef USE_APPLE_SECTRUST
if(!verified && conn_config->verifypeer && ssl_config->native_ca_store) {
result = ossl_apple_verify(cf, data, octx, peer, &verified);
if(verified) {
sectrust_verified = TRUE;
}
}
#endif
...
if(conn_config->verifystatus &&
#ifdef USE_APPLE_SECTRUST
!sectrust_verified && /* <-- skips the OCSP check */
#endif
!octx->reused_session) {
result = verifystatus(cf, data, octx); /* never reached */
}
```
The assumption is "SecTrust already handled OCSP." But SecTrust only receives a stapled OCSP response when `ocsp_len > 0` (in `ossl_apple_verify`). If the server doesn't staple, `SSL_get_tlsext_status_ocsp_resp()` returns -1, which is clamped to 0, and `SecTrustSetOCSPResponse()` is never called. SecTrust's default revocation policy (`kSecRevocationUseAnyAvailableMethod`) is best-effort — `kSecRevocationRequirePositiveResponse` is explicitly `#if 0` in `apple.c`.
Result: no OCSP enforcement happens at all.
## Affected Versions
Introduced in commit `b4630ed8fa` (2025-10-31). Present in curl 8.17.0, 8.18.0, 8.19.0, and current master.
## Steps To Reproduce
### Step 1: Build two versions of curl
Tested on curl master at commit `bfcc1c6eb4`. The bug was introduced in commit `b4630ed8fa` (2025-10-31), so any version >= 8.17.0 is affected.
**Build A — OpenSSL only (control):**
```
cmake -DCURL_USE_OPENSSL=ON -DUSE_APPLE_SECTRUST=OFF
```
```
curl --version
curl 8.20.0-DEV (Darwin) libcurl/8.20.0-DEV OpenSSL/3.6.1 zlib/1.2.12 brotli/1.2.0 zstd/1.5.7 libidn2/2.3.8 libpsl/0.21.5 nghttp2/1.68.0
Release-Date: [unreleased]
Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns ldap ldaps mqtt mqtts pop3 pop3s rtsp smb smbs smtp smtps telnet tftp ws wss
Features: alt-svc AsynchDNS brotli HSTS HTTP2 HTTPS-proxy IDN IPv6 Largefile libz NTLM PSL SSL threadsafe TLS-SRP UnixSockets zstd
```
**Build B — OpenSSL + Apple SecTrust (test):**
```
cmake -DCURL_USE_OPENSSL=ON -DUSE_APPLE_SECTRUST=ON
```
```
curl --version
curl 8.20.0-DEV (Darwin) libcurl/8.20.0-DEV OpenSSL/3.6.1 zlib/1.2.12 brotli/1.2.0 zstd/1.5.7 libidn2/2.3.8 libpsl/0.21.5 nghttp2/1.68.0
Release-Date: [unreleased]
Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns mqtt mqtts pop3 pop3s rtsp smtp smtps telnet tftp ws wss
Features: alt-svc AppleSecTrust AsynchDNS brotli HSTS HTTP2 HTTPS-proxy IDN IPv6 Largefile libz PSL SSL threadsafe TLS-SRP UnixSockets zstd
```
Note `AppleSecTrust` in the Features line of Build B.
### Step 2: Generate test certificates
```bash
# Generate CA
openssl req -x509 -newkey rsa:2048 -days 30 -nodes \
-keyout ca-key.pem -out ca.pem -subj "/CN=PoC Test CA"
# Generate server cert signed by CA (SAN=localhost)
openssl req -newkey rsa:2048 -nodes \
-keyout server-key.pem -out server.csr -subj "/CN=localhost"
openssl x509 -req -days 30 -in server.csr \
-CA ca.pem -CAkey ca-key.pem -CAcreateserial \
-out server.pem -extfile <(printf "subjectAltName=DNS:localhost")
```
### Step 3: Add CA to macOS Keychain
Add the CA to the macOS login keychain as trusted:
```bash
security add-trusted-cert -r trustRoot -k ~/Library/Keychains/login.keychain-db ca.pem
```
### Step 4: Start test server (no OCSP stapling)
`openssl s_server` does not staple OCSP by default:
```bash
openssl s_server -cert server.pem -key server-key.pem -accept 4433 -www
```
### Step 5: Run the three tests
**Test 1 — Control (Build A, OpenSSL only):**
```bash
curl -v --cert-status --cacert ca.pem https://localhost:4433/
```
**Test 2 — Bug (Build B, SecTrust):**
```bash
curl -v --cert-status --ca-native https://localhost:4433/
```
**Test 3 — Sanity (Build B, SecTrust, no --cert-status):**
```bash
curl -v --ca-native https://localhost:4433/
```
Clean up when done:
```bash
security delete-certificate -c "PoC Test CA" ~/Library/Keychains/login.keychain-db
```
## Results
| Test | Build | Flags | Result | Expected |
|------|-------|-------|--------|----------|
| 1 | OpenSSL only | `--cert-status --cacert ca.pem` | **FAIL (exit 91)**: "No OCSP response received" | Correct — OCSP enforced |
| 2 | OpenSSL + SecTrust | `--cert-status --ca-native` | **SUCCESS (exit 0)** | WRONG — OCSP bypassed |
| 3 | OpenSSL + SecTrust | `--ca-native` | **SUCCESS (exit 0)** | Correct — no OCSP requested |
Test 1 verbose output (relevant lines):
```
* OpenSSL verify result: 0
* SSL certificate verified via OpenSSL.
* No OCSP response received
* closing connection #0
curl: (91) No OCSP response received
```
Test 2 verbose output (relevant lines):
```
* OpenSSL verify result: 14
* SSL certificate verified via Apple SecTrust.
* Established connection to localhost (::1 port 4433) from ::1 port 49751
```
No OCSP check occurs. The connection succeeds despite `--cert-status` being set and the server providing no OCSP staple.
## Impact
## Summary:
A user who sets `--cert-status` / `CURLOPT_SSL_VERIFYSTATUS` expects curl to abort the connection if the server does not provide a valid OCSP stapled response. This is documented behavior: "If this option is enabled and the server sends an invalid response, or no response at all is received, the verification fails."
When Apple SecTrust handles verification (build with `USE_APPLE_SECTRUST`, runtime with `--ca-native`), this guarantee is silently violated. The OCSP stapling check is skipped entirely, and the connection proceeds as if `--cert-status` was never set.
This is the same vulnerability class as CVE-2024-8096 (OCSP stapling bypass with GnuTLS) and CVE-2024-0853 (OCSP verification bypass with TLS session reuse).
Actions
View on HackerOneReport Stats
- Report ID: 3694390
- State: Closed
- Substate: resolved