Skip to content

CWE-297: Improper Validation of Certificate with Host Mismatch

Overview

A TLS client that does not check that the certificate identifies the host it is connecting to will accept any valid certificate, including one an attacker holds for a different domain, which allows a man-in-the-middle attack. Modern server certificates identify the host with Subject Alternative Name (SAN) entries; Common Name-only certificates are legacy and should be replaced rather than treated as the compatibility target.

Relationship to Other CWEs

OWASP Classification

A07:2025 - Authentication Failures

Risk

High: An attacker holding a valid certificate for any domain can impersonate the server, read the credentials and data the client sends, and take over its sessions. Because any valid certificate is accepted regardless of hostname, TLS authenticates nobody.

Remediation Steps

Core Principle: Never establish a TLS connection unless the TLS stack has checked the certificate's hostname against the peer the application asked for; do not bypass or weaken that check.

Locate the hostname validation vulnerability

  • Start from the file and line in the finding, then look at the TLS client code around it: HTTPS requests, or anything else that establishes a secure connection
  • Find where hostname verification is off: a HostnameVerifier that returns true, check_hostname=False, a wrap_socket() call with no server_hostname, a raw SSLSocket with no endpoint identification algorithm, or verification disabled outright with verify=False / SSL_VERIFY_NONE
  • Check every place the process creates a TLS client or context, not only the one the finding names

Always verify hostname (Primary Defense)

  • HTTP clients: verify the hostname by default - requests and urllib3 in Python, OkHttp, Apache HttpClient and java.net.http.HttpClient in Java. Below the HTTP client the default runs the other way; see the next bullet.
  • Switch the name check on for raw TLS sockets: a Java SSLSocket and a Python SSLContext.wrap_socket() called without server_hostname both verify the chain and skip the name, which authenticates nobody. Nothing is disabled in either case and no verify=False rule matches. In Java, set SSLParameters.setEndpointIdentificationAlgorithm("HTTPS") and apply the parameters to the socket before startHandshake(); in Python, pass server_hostname=host to wrap_socket() rather than clearing check_hostname. See CWE-295 Java and CWE-295 Python.
  • Never disable hostname verification: remove trust-all HostnameVerifier implementations, check_hostname=False, assert_hostname=False, and custom validators that skip the name check
  • SAN, not Common Name: the library should compare the hostname with the certificate's Subject Alternative Names; replace legacy Common Name-only certificates instead of weakening validation to accept them
  • Use the library's built-in hostname verification: custom validators often have security flaws of their own; write one only when there is no alternative

Use secure TLS configuration

  • Chain-verification switches: verify=False (Python requests), ssl.CERT_NONE and OpenSSL's SSL_VERIFY_NONE turn certificate verification off entirely, so they take the name check with them. Removing them is necessary, but on its own it does not give you a name check - see the next bullet.
  • Hostname-verification switches: in the JDK, a HostnameVerifier whose verify() returns true; the JDK itself has no ALLOW_ALL constant. In Apache HttpClient, NoopHostnameVerifier.INSTANCE; the 4.x name ALLOW_ALL_HOSTNAME_VERIFIER was deprecated in 4.4 but is still a public field throughout the 4.5.x line, so a finding on 4.5 will name it, and it is gone in 5.x. In Python, check_hostname = False or assert_hostname=False. In OpenSSL the name check is not a switch at all: it is opt-in through SSL_set1_host() or X509_VERIFY_PARAM_set1_host(), and SSL_VERIFY_PEER on its own gives a fully validated chain with no name check whatsoever.
  • Trust store: rely on the one the runtime already uses rather than a hand-built one, and note that it is not always the OS store - see CWE-295
  • Verify the whole chain: not just the leaf certificate

Handle certificate errors properly

  • Do not catch and ignore SSL exceptions; let the connection fail, and treat the failure as a security issue rather than something to work around
  • Log the hostname, certificate details, and error message when validation fails, so the failure can be investigated
  • Alert on frequent certificate errors, which can indicate a MITM attempt

Pin public keys for critical connections (Defense in Depth)

  • Pin expected public key/SPKI hashes for high-security connections
  • Validate against pinned values in addition to normal hostname verification
  • Update pins during key rotation and maintain backup pins for smooth rotation
  • Use certificate transparency logs to detect mis-issued certificates

Test the hostname verification fix

  • Confirm a valid public endpoint still connects (https://badssl.com/ returns 200). A client that rejects every certificate passes every test below, so assert the accept first
  • Verify connections fail when certificate hostname doesn't match (https://wrong.host.badssl.com/), through each TLS client the process creates rather than only the one the finding named
  • Test with self-signed certificates (should fail unless explicitly trusted)
  • Test with expired certificates (should fail)
  • Test with valid certificate for different domain (should fail)
  • Re-scan with security scanner to confirm the issue is resolved

Common Vulnerable Patterns

  • A HostnameVerifier that returns true, or NoopHostnameVerifier.INSTANCE
  • check_hostname = False or assert_hostname=False
  • SSLContext.wrap_socket() called without server_hostname
  • A raw SSLSocket with no endpoint identification algorithm set
  • OpenSSL verification with SSL_VERIFY_PEER but no SSL_set1_host()
  • Custom validators that walk the chain and never compare the name
  • verify=False, CERT_NONE or SSL_VERIFY_NONE, which disable chain verification and take the name check with them

Additional Resources