✓ProveIt
Examples / Report #3150884 Saved analysis

CVE-2025-4947: QUIC certificate check skip with wolfSSL

curl · 2025-05-1713.2s analysis · $0.017 in model calls

What the report claims

The report claims that when using WolfSSL as the TLS backend and connecting to an IP address over HTTP/3, curl skips verification of the certificate's CN or SAN because peer->sni is NULL, leading to improper host validation.

Compare with curl's recorded outcome

Known vulnerability

A real vulnerability: CVE-2025-4947 QUIC certificate check skip with wolfSSL

Shown for comparison after analysis. The pipeline did not see this label.

ProveIt's finding

Needs human review

The available evidence does not settle the report. A maintainer should investigate.

Judgment withdrawn. The answer failed the evidence check.
See the withdrawn model reasoning

The following reasoning failed the citation check and does not support the final finding.

  • The WolfSSL verification code in Curl_vquic_tls_verify_peer (lib/vquic/vquic-tls.c:179-191) only calls wolfSSL_X509_check_host when peer->sni is non-NULL.
  • When connecting to an IP address, SNI is typically not sent, so peer->sni would be NULL, causing the entire hostname/IP verification to be skipped.
  • The connection then succeeds (returns CURLE_OK) without any certificate host matching, allowing a MITM with a mismatched certificate to go undetected.
  • This differs from OpenSSL backend behavior (which verifies IP addresses via X509_check_ip) and HTTP/1.1 code paths, confirming the inconsistency the reporter observed.
  • This is a security issue: an attacker who can redirect traffic to a server with a valid certificate for a different host/IP can intercept QUIC connections to IP addresses when WolfSSL is used.
What still needs checking
  • Confirmation that peer->sni is indeed NULL when connecting to an IP address in the QUIC code path (requires checking the SNI handling code not provided).
How this analysis ran 5 claims · 6 citations verified

Evidence check: judge quoted an external source that does not say that (https://docs.openssl.org/3.5/man3/SSL_set1_host)

Checked against curl master on 2025-05-17 (0013bbdfb8c8). Test evaluation split. Citation verification checks that a referenced line was in the evidence; it does not prove the model interpreted it correctly.

1 · Grounding
grounded
no model · 8 references checked out, 0 did not
2 · Claims
NVIDIA-Nemotron-3-Nano-30B-A3B
5 claims · 1762 tokens · $0.0002
3 · Evidence
1 code snippets
real curl source at 0013bbdfb8c8 · 6 docs via Tavily
4 · Judgment
Nemotron-3-Ultra-550b-a55b
10885 tokens · 10.0s · $0.0171
5 · Receipts
6 of 6 citations verified
every citation must point at code the judge was shown
Inspect the withdrawn draft reply

This draft belongs to the withdrawn judgment. It may contain unsupported claims.

Thank you for the detailed report. The code in lib/vquic/vquic-tls.c:181-189 confirms that WolfSSL's certificate hostname verification is only performed when peer->sni is non-NULL. When connecting to an IP address, SNI is typically absent, so peer->sni is likely NULL, causing the verification to be skipped entirely. This allows a certificate mismatch to go undetected for QUIC connections to IP addresses with WolfSSL. We will investigate the fix, which should verify against the configured hostname/IP (not just SNI) similar to how OpenSSL backend handles it.

Inspect all claims and source code 5 claims · 1 code excerpts

This model judgment was withdrawn. The claim assessments below are preserved for inspection and may be wrong.

Report claims

C1flaw supported

CN or SAN in the certificate is not verified when connecting to an IP address over HTTP/3 with WolfSSL backend

Read the reasoning

The code at lines 181-189 shows that when USE_WOLFSSL is defined, the certificate hostname verification (wolfSSL_X509_check_host) is only executed if peer->sni is non-NULL. If peer->sni is NULL (as when connecting to an IP address), the entire verification block is skipped.

C2location supported

The verification code is located in Curl_vquic_tls_verify_peer() under the USE_WOLFSSL block

Read the reasoning

The WolfSSL-specific verification code is located in Curl_vquic_tls_verify_peer at lines 179-191.

C3trigger not verifiable

Specifying an IP address instead of a domain name causes peer->sni to be NULL

Read the reasoning

The provided code does not show where peer->sni is set or why it would be NULL for IP addresses. This depends on QUIC/TLS handshake code not included in the source excerpt. The claim is plausible (SNI is for domain names, not IP addresses) but cannot be verified from the given code alone.

C4impact supported

The connection succeeds without proper host validation, allowing a certificate mismatch to go undetected

Read the reasoning

When peer->sni is NULL, the function returns CURLE_OK (line 162, 196) without performing any hostname or IP address verification against the peer certificate, allowing a mismatched certificate to be accepted.

C5reproduction not verifiable

Run curl --http3 https://<IP_address> where the IP is obtained from a domain name, using a curl build with WolfSSL backend

Read the reasoning

The reproduction steps describe a plausible scenario but cannot be verified against the provided code alone; they require a live WolfSSL build and network test.

What the report says about other projects

confirmed OpenSSL's SSL_set1_host sets the expected DNS hostname or IP address for certificate verification; when a nonempty host is specified, verification automatically checks the peer hostname via X509_check_host. When an IP address and/or multiple hostnames are configured, the peer is considered verified when any of these matches.

“SSL_set1_host() sets in the verification parameters of *s* the expected DNS hostname or IP address to *host*... When an IP address and/or multiple hostnames are configured, the peer is considered verified when any of these matches.” source

confirmed X509_check_host checks if the certificate Subject Alternative Name (SAN) or Subject CommonName (CN) matches the specified hostname, which must be encoded in the preferred name syntax. X509_check_ip checks IP address matching.

“X509_check_host() checks if the certificate Subject Alternative Name (SAN) or Subject CommonName (CN) matches the specified hostname... int X509_check_ip(X509 *x, const unsigned char *address, size_t addresslen, unsigned int flags);” source

Read the original report

Full report on HackerOne ↗

## Summary: When using WolfSSL as the TLS backend, there is an issue where the CN or SAN in the certificate is not verified when connecting to an IP address over HTTP/3. wolfSSL_X509_check_host is only called when `peer->sni` is not NULL. However, when an IP address is specified, `peer->sni` is NULL, so the verification does not occur. Curl_vquic_tls_verify_peer() ``` #elif defined(USE_WOLFSSL) (void)data; if(conn_config->verifyhost) { if(peer->sni) { WOLFSSL_X509* cert = wolfSSL_get_peer_certificate(ctx->wssl.ssl); if(wolfSSL_X509_check_host(cert, peer->sni, strlen(peer->sni), 0, NULL) == WOLFSSL_FAILURE) { result = CURLE_PEER_FAILED_VERIFICATION; } wolfSSL_X509_free(cert); } } #endif ``` ## Affected version ``` curl -V WARNING: this libcurl is Debug-enabled, do not use in production curl 8.13.0 (x86_64-pc-linux-gnu) libcurl/8.13.0 wolfSSL/5.8.0 zlib/1.3.1 libidn2/2.3.8 libpsl/0.21.2 ngtcp2/1.13.0-DEV nghttp3/1.1 Release-Date: 2025-04-02 Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns mqtt pop3 pop3s rtsp smtp smtps telnet tftp ws wss Features: alt-svc AsynchDNS Debug HSTS HTTP3 HTTPS-proxy IDN IPv6 Largefile libz PSL SSL threadsafe TrackMemory UnixSockets ``` ## Steps To Reproduce: I will explain using a connection to google.com as an example. 1. Prepare curl with WolfSSL backend. 1. To resolve the domain name google.com and obtain its IP address for testing purposes(142.251.222.14). 1. curl --http3 https://142.251.222.14 When an IP address is specified, it should result in an error during CN/SAN verification, but no error occurs. An error occurs when using HTTP/1.1. An error occurs when the TLS backend is OpenSSL. ## Impact CWE-297: Improper Validation of Certificate with Host Mismatch

Source code

lib/vquic/vquic-tls.clines 156–197 · definition of Curl_vquic_tls_verify_peer
156CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx,
C2: Function Curl_vquic_tls_verify_peer definition starts here
157 struct Curl_cfilter *cf,
158 struct Curl_easy *data,
159 struct ssl_peer *peer)
160{
161 struct ssl_primary_config *conn_config;
162 CURLcode result = CURLE_OK;
163
164 conn_config = Curl_ssl_cf_get_primary_config(cf);
165 if(!conn_config)
166 return CURLE_FAILED_INIT;
167
168#ifdef USE_OPENSSL
169 (void)conn_config;
170 result = Curl_oss_check_peer_cert(cf, data, &ctx->ossl, peer);
171#elif defined(USE_GNUTLS)
172 if(conn_config->verifyhost) {
173 result = Curl_gtls_verifyserver(data, ctx->gtls.session,
174 conn_config, &data->set.ssl, peer,
175 data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
176 if(result)
177 return result;
178 }
179#elif defined(USE_WOLFSSL)
C2: #elif defined(USE_WOLFSSL) block starts here
180 (void)data;
181 if(conn_config->verifyhost) {
C4: conn_config->verifyhost is checked but the actual verification is gated on peer->sni
182 if(peer->sni) {
C1: wolfSSL_X509_check_host is only called inside 'if(peer->sni)' block
C4: If peer->sni is NULL, no certificate hostname/IP check occurs at all
183 WOLFSSL_X509* cert = wolfSSL_get_peer_certificate(ctx->wssl.ssl);
184 if(wolfSSL_X509_check_host(cert, peer->sni, strlen(peer->sni), 0, NULL)
C1: The hostname verification uses peer->sni as the name to check against
185 == WOLFSSL_FAILURE) {
186 result = CURLE_PEER_FAILED_VERIFICATION;
187 }
188 wolfSSL_X509_free(cert);
189 }
190
191 }
192#endif
193 /* on error, remove any session we might have in the pool */
194 if(result)
195 Curl_ssl_scache_remove_all(cf, data, peer->scache_key);
196 return result;
197}