SecureBlockLog inStart a pentest
Vulnerability Repository
CriticalCryptography

Certificate Validation Bypass

Applications that skip or improperly implement TLS certificate validation are vulnerable to man-in-the-middle attacks, allowing traffic interception and credential theft.

CVSS 9.1CWE CWE-295OWASP A02:2021 — Cryptographic Failures

Description

Certificate validation bypass (CWE-295 — Improper Certificate Validation) occurs when a client application establishes a TLS connection but fails to properly verify the server's X.509 certificate — specifically, that the certificate is issued by a trusted Certificate Authority, has not expired, has not been revoked, and matches the hostname being connected to. Without this validation, TLS provides encryption but no authentication: the client cannot distinguish the legitimate server from an attacker's proxy.

This vulnerability is rated critical (CVSS 9.1) and classified under A02:2021 — Cryptographic Failures because the fundamental purpose of TLS — verifying you're talking to the right server — is completely defeated. An attacker with a network-position advantage (on the same Wi-Fi network, ISP, or VPN) can intercept all "encrypted" traffic transparently. Every credential, session token, API key, and piece of sensitive data transmitted becomes visible.

Certificate validation bypass is extraordinarily common in mobile applications, SDKs, and IoT devices. Developers disable validation to "fix" connection errors during development or to work around self-signed certificates in test environments — then accidentally ship the disabled validation to production. It also appears in back-end service-to-service communication where developers deem internal traffic "safe."

How It Works

Mobile app validation bypass is the most common form. An Android developer encounters an SSL error during development and adds:

// Vulnerable Android code — disables all certificate validation
TrustManager[] trustAllCerts = new TrustManager[]{
    new X509TrustManager() {
        public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; }
        public void checkClientTrusted(X509Certificate[] certs, String authType) {}
        public void checkServerTrusted(X509Certificate[] certs, String authType) {}
    }
};
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Also common: setDefaultHostnameVerifier((hostname, session) -> true);

Both checkServerTrusted implementations are empty — they accept any certificate from any CA (or no CA) for any hostname.

In Python, the equivalent is:

# Vulnerable
requests.get("https://api.example.com", verify=False)
import ssl
ssl._create_default_https_context = ssl._create_unverified_context

With validation disabled, the attacker sets up mitmproxy or Burp Suite on the network and generates a self-signed certificate for api.example.com. The client accepts it without question, and all traffic is decrypted and re-encrypted by the proxy — fully transparent to the user.

Hostname verification bypass is a subtler variant where certificate chain validation is correct but hostname verification is skipped. The server has a valid certificate issued by a trusted CA, but it's for other-server.com. A client that verifies the chain but not the hostname will accept this certificate for api.example.com — allowing a legitimate certificate holder for any domain to MITM connections.

Pinning bypass — applications that implement certificate or public key pinning raise the bar by checking that the server's certificate or key matches a pre-trusted pin. However, pinning is commonly bypassed by tools like Frida (dynamic instrumentation), Objection (iOS/Android pinning bypass automation), and apk-mitm (patches APKs to remove pinning).

Impact

  • Credential interception — all usernames, passwords, and API keys transmitted over the "encrypted" connection are visible in plaintext to the MITM.
  • Session token theft — session cookies and bearer tokens are captured, enabling account takeover without user interaction.
  • Complete API traffic inspection — all data exchanged with backend APIs, including PII and proprietary business data, is readable.
  • Response manipulation — the attacker can modify API responses in transit, injecting malicious data or manipulating application logic.
  • Mutual TLS bypass — if the server requires client certificates, a proxying MITM defeats the server's authentication as well.
  • Sensitive data exfiltration — all data exchanged by the application during normal use (medical records, financial data, messages) is exposed.

Detection

  1. Set up a MITM proxy (Burp Suite or mitmproxy) and configure your test device to route traffic through it. If the application functions normally without installing a custom CA, certificate validation is bypassed.
  2. Use Frida/Objection for mobile testingobjection -g <app_bundle> explore followed by android sslpinning disable or ios sslpinning disable. If traffic becomes visible in Burp after this, pinning was the only control and the underlying validation was bypassable.
  3. Review source code — search for verify=False, InsecureRequestWarning, trustAllCerts, empty TrustManager implementations, setDefaultHostnameVerifier(ALLOW_ALL_HOSTNAME_VERIFIER), and NSAllowsArbitraryLoads in iOS plist files.
  4. Check iOS ATS configuration — review Info.plist for NSAppTransportSecurity entries. NSAllowsArbitraryLoads: true disables ATS and certificate validation for all connections.
  5. Test with an expired or wrong-hostname certificate — temporarily point a test environment to serve an expired or mismatched certificate and verify the client rejects the connection.

Remediation

Enable and never disable certificate validation. Remove all verify=False, empty TrustManager, and ALLOW_ALL_HOSTNAME_VERIFIER code. In Python:

# Always verify — this is the default, but make it explicit
response = requests.get("https://api.example.com", verify=True)

For self-signed certificates in non-production, distribute the CA certificate and configure the client to trust only that CA — never disable validation:

response = requests.get("https://api.staging.com", verify="/path/to/staging-ca.pem")

Implement certificate pinning for high-value mobile apps. Pin the public key (preferred over the full certificate) of the server's certificate or its issuing CA. Use libraries like TrustKit (iOS/Android) for robust pinning with reporting and pin rotation support.

Enable iOS App Transport Security. Ensure NSAllowsArbitraryLoads is false in Info.plist. Use specific per-domain exceptions only if required, not a blanket disable.

Configure hostname verification explicitly in any HTTP client library that does not enable it by default. Verify both the CA chain and the hostname in every TLS connection.

Ready when you are
Scope a pentest in the next two minutes.
Start scoping