Improper Certificate Validation

Description

Improper Certificate Validation occurs when software does not validate, or incorrectly validates, a digital certificate. Certificates are used to establish trusted communication channels, verify identities, and ensure data integrity. When validation is missing or flawed, attackers can perform man-in-the-middle (MitM) attacks by presenting fraudulent certificates, intercepting encrypted communications, impersonating trusted servers, or injecting malicious content. Common issues include disabled hostname verification, accepting self-signed certificates, ignoring certificate expiration, and trusting invalid certificate chains.

Risk

Certificate validation failures directly enable man-in-the-middle attacks against otherwise encrypted communications. Attackers can intercept HTTPS traffic, steal credentials, inject malicious payloads, and impersonate legitimate services. The Netty framework's disabled hostname verification by default has affected numerous Java applications. Mobile apps frequently ship with certificate validation disabled for development and never re-enabled. Industrial control systems like Siemens Solid Edge have been vulnerable, enabling attacks on engineering workstations. Financial and healthcare data protected only by "TLS" becomes completely exposed when certificate validation fails.

Solution

Always validate certificates completely: verify the certificate chain up to a trusted root CA, check certificate expiration, validate that the hostname matches the certificate's Subject Alternative Names or Common Name, and verify certificate revocation status (CRL/OCSP). Use established TLS libraries with secure defaults. Never disable certificate validation in production. Implement certificate pinning for high-security applications. Test certificate validation explicitly during security assessments. Configure TLS properly with strong cipher suites.

Common Consequences

ImpactDetails
ConfidentialityScope: Data Interception

Attackers intercept and decrypt all "encrypted" communications when they can present forged certificates.
IntegrityScope: Data Manipulation

MitM attackers can modify data in transit, injecting malicious content or altering transactions.
AuthenticationScope: Identity Spoofing

Attackers impersonate legitimate servers, directing users to malicious services.

Example Code + Solution Code

Vulnerable Code

// VULNERABLE: Disabled hostname verification
import javax.net.ssl.*;

SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, new TrustManager[] {
    new X509TrustManager() {
        public void checkClientTrusted(X509Certificate[] chain, String auth) {}
        public void checkServerTrusted(X509Certificate[] chain, String auth) {}
        public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
    }
}, null);

// Accepts ANY certificate!
HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
# VULNERABLE: Disabled certificate verification
import requests

# verify=False disables ALL certificate validation
response = requests.get('https://api.example.com', verify=False)

# VULNERABLE: Custom SSL context with no verification
import ssl
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
// VULNERABLE: Node.js with disabled verification
const https = require('https');

const agent = new https.Agent({
    rejectUnauthorized: false  // Accepts invalid certificates!
});

https.get('https://api.example.com', { agent }, (res) => {
    // ...
});

// VULNERABLE: Environment variable
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';  // Never do this!

Fixed Code

// SAFE: Proper certificate validation
import javax.net.ssl.*;
import java.security.KeyStore;

public class SecureHttpClient {
    public HttpsURLConnection createConnection(URL url) throws Exception {
        // Load trusted certificates
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        trustStore.load(getClass().getResourceAsStream("/truststore.jks"),
                       "password".toCharArray());

        TrustManagerFactory tmf = TrustManagerFactory.getInstance(
            TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(trustStore);

        SSLContext ctx = SSLContext.getInstance("TLS");
        ctx.init(null, tmf.getTrustManagers(), null);

        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
        conn.setSSLSocketFactory(ctx.getSocketFactory());
        // Default hostname verifier validates hostname
        return conn;
    }
}

// SAFE: Certificate pinning
public class PinningTrustManager implements X509TrustManager {
    private static final String EXPECTED_PIN = "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";

    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        // Verify certificate chain first
        defaultTrustManager.checkServerTrusted(chain, authType);

        // Then verify pin
        String pin = getPin(chain[0]);
        if (!EXPECTED_PIN.equals(pin)) {
            throw new CertificateException("Certificate pin mismatch");
        }
    }
}
# SAFE: Proper certificate verification (default)
import requests

# verify=True is the default - validates certificates
response = requests.get('https://api.example.com')  # Secure by default

# SAFE: Custom CA bundle
response = requests.get('https://api.example.com',
                        verify='/path/to/ca-bundle.crt')

# SAFE: Certificate pinning with requests
from requests.adapters import HTTPAdapter
from urllib3.util.ssl_ import create_urllib3_context

class PinningAdapter(HTTPAdapter):
    def __init__(self, expected_fingerprint):
        self.expected_fingerprint = expected_fingerprint
        super().__init__()

    def init_poolmanager(self, *args, **kwargs):
        ctx = create_urllib3_context()
        kwargs['ssl_context'] = ctx
        return super().init_poolmanager(*args, **kwargs)

    def cert_verify(self, conn, url, verify, cert):
        super().cert_verify(conn, url, verify, cert)
        # Additional fingerprint verification
        actual = conn.sock.getpeercert(binary_form=True)
        if hashlib.sha256(actual).hexdigest() != self.expected_fingerprint:
            raise SSLError("Certificate fingerprint mismatch")
// SAFE: Node.js with proper validation (default)
const https = require('https');

// Default behavior validates certificates
https.get('https://api.example.com', (res) => {
    // Certificate validated automatically
});

// SAFE: Certificate pinning
const tls = require('tls');
const https = require('https');

const EXPECTED_FINGERPRINT = '00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF';

const agent = new https.Agent({
    checkServerIdentity: (host, cert) => {
        const fingerprint = cert.fingerprint256;
        if (fingerprint !== EXPECTED_FINGERPRINT) {
            throw new Error('Certificate fingerprint mismatch');
        }
        // Also perform standard hostname verification
        return tls.checkServerIdentity(host, cert);
    }
});

Exploited in the Wild

Siemens Solid Edge (Siemens, 2025)

CVE-2025-40744 in Siemens Solid Edge SE2025 allows MitM attacks due to improper client certificate validation when connecting to the License Service, with CVSS 7.5 high severity.

Fortinet FortiWeb WAF (Fortinet, 2024)

CVE-2024-33509 in FortiWeb allows MitM attackers to intercept and tamper with WAF communications due to improper certificate validation when fetching external data.

Netty Framework (Netty, Multiple)

Certificate hostname validation disabled by default in Netty 4.1.x affected numerous Java applications including Keycloak, making them vulnerable to MitM attacks.


Tools to test/exploit

  • SSLyze — analyze TLS configuration and certificate validation.

  • testssl.sh — TLS/SSL testing tool.

  • mitmproxy — test certificate validation by attempting MitM.


CVE Examples


References

  1. MITRE. "CWE-295: Improper Certificate Validation." https://cwe.mitre.org/data/definitions/295.html

  2. OWASP. "Transport Layer Protection Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html