Improper certificate validation occurs when software fails to verify that a TLS/SSL certificate is legitimate before trusting it. This allows an attacker…
Improper certificate validation occurs when software fails to verify that a TLS/SSL certificate is legitimate before trusting it. This allows an attacker positioned between a client and server to intercept encrypted connections by presenting a forged or self-signed certificate. The application accepts it without question, exposing all transmitted data to eavesdropping and manipulation.
02How It Happens
When a client connects to a server over HTTPS, the server presents a certificate proving its identity. The client must verify that the certificate is valid, signed by a trusted authority, and matches the server's hostname. If the application skips these checks—or performs them incorrectly—it will trust any certificate, including ones created by an attacker. Common mistakes include disabling certificate validation during development and forgetting to re-enable it in production, accepting self-signed certificates without explicit user consent, or failing to check that the certificate's Common Name or Subject Alternative Name matches the hostname being accessed.
03Real-World Impact
An attacker on the same network (or controlling network infrastructure) can perform a man-in-the-middle attack, intercepting HTTPS traffic and reading or modifying sensitive data in transit: login credentials, API tokens, personal information, or financial details. The victim sees no warning because the application silently accepts the attacker's certificate. This is particularly dangerous for mobile apps, desktop clients, and backend services that make outbound HTTPS requests, since users have no browser address bar to alert them to the problem.
04Vulnerable & Fixed Patterns
Vulnerable pattern
import requests
import ssl
# Vulnerable: disabling certificate verification
response = requests.get(
'https://api.example.com/data',
verify=False # Accepts any certificate, including forged ones
)
# Also vulnerable: custom SSL context that doesn't validate
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
Why it's vulnerable: Setting verify=False or disabling check_hostname and verify_mode tells the client to accept any certificate without validation, opening the connection to man-in-the-middle attacks.
Fixed pattern
import requests
import ssl
# Fixed: use default certificate validation (enabled by default)
response = requests.get('https://api.example.com/data')
# verify=True is the default; omit it or set it explicitly
# Fixed: proper SSL context with validation enabled
context = ssl.create_default_context()
# check_hostname and verify_mode are True/CERT_REQUIRED by default
# Optionally load custom CA bundle if needed:
# context.load_verify_locations('/path/to/ca-bundle.crt')
Why it's vulnerable: Setting CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST to false disables all certificate validation, allowing forged certificates to be accepted.
Never disable certificate validation in production code. If you must do so during development, use a separate configuration flag and ensure it defaults to true in production builds.
Verify hostname matching. Ensure the certificate's CN or SAN matches the hostname you are connecting to; do not skip this step.
Use system certificate stores. Rely on the operating system's trusted CA bundle rather than bundling your own, unless you have a specific security reason to do otherwise.
Test HTTPS connections with invalid certificates. Verify that your application rejects self-signed, expired, or mismatched certificates during testing.
Keep certificate libraries updated. Use the latest versions of OpenSSL, Python's certifi, or PHP's CA bundle to ensure you have current root certificates.
Audit third-party libraries. Check that any HTTP client library you use (requests, Guzzle, cURL wrapper) has certificate validation enabled by default.
06Signs You May Already Be Affected
Review your codebase for calls to requests.get() with verify=False, cURL operations with CURLOPT_SSL_VERIFYPEER or CURLOPT_SSL_VERIFYHOST set to false, or SSL context creation with check_hostname = False or verify_mode = ssl.CERT_NONE. If you find these patterns in production code, they represent an active vulnerability. Additionally, if your application connects to external APIs or services over HTTPS and you have not explicitly tested its behavior against invalid certificates, assume validation may be misconfigured.