CWE-296: Improper Certificate Validation (Trust Chain)
Overview
Improper certificate validation of the trust chain occurs when applications fail to verify that an X.509 certificate chains properly to a trusted root Certificate Authority (CA). This allows attackers to use self-signed certificates, certificates signed by untrusted CAs, or certificates with broken chain of trust to impersonate legitimate servers in man-in-the-middle (MITM) attacks. The vulnerability commonly arises from disabled certificate validation during development that remains in production, custom TLS implementations that skip chain verification, or incorrect trust store configuration.
OWASP Classification
A04:2025 - Cryptographic Failures
Risk
High: Enables man-in-the-middle attacks where attackers intercept encrypted communications, steal credentials, session tokens, sensitive data, and inject malicious content. Particularly dangerous on public Wi-Fi, compromised networks, or when attackers control network infrastructure (DNS, routing).
Remediation Steps
Core principle: Always validate the complete certificate trust chain to a known trusted root CA; never disable certificate validation or trust unverified certificates in production.
Enable Full Certificate Chain Validation
Ensure the TLS/SSL library validates:
- Certificate chains to a trusted root CA
- Certificate is not self-signed (unless explicitly trusted)
- Intermediate certificates are included and valid
- Certificate has not expired
- Certificate has not been revoked (CRL/OCSP)
Use Proper TLS Configuration
# VULNERABLE - disables chain validation
import requests
requests.get(url, verify=False) # NEVER do this!
# SECURE - validates full chain
requests.get(url, verify=True) # Or omit verify (True is default)
//VULNERABLE - Node.js disables validation
const https = require('https');
https.get(url, {
rejectUnauthorized: false // DANGEROUS!
});
// SECURE - proper validation
https.get(url, {
rejectUnauthorized: true // Or omit (true is default)
});
Pin Certificates for Critical Connections (Advanced)
For high-security scenarios, pin expected certificates:
import ssl, certifi
context = ssl.create_default_context(cafile=certifi.where())
# Optionally pin specific certificate fingerprint
context.check_hostname = True
context.verify_mode = ssl.CERT_REQUIRED
Use System Trust Store
Rely on operating system or language-provided trust stores:
- Python: certifi, ssl.create_default_context()
- Node.js: Default trust store (or ca option with Mozilla CA bundle)
- Java: JRE cacerts keystore
- .NET: Windows Certificate Store
Test Certificate Validation
Verify your implementation rejects invalid certificates:
# Test with self-signed certificate (should fail)
curl https://self-signed.badssl.com/
# Test with expired certificate (should fail)
curl https://expired.badssl.com/
# Test with wrong host (should fail)
curl https://wrong.host.badssl.com/
Dynamic Scan Guidance
For guidance on remediating this CWE when detected by dynamic (DAST) scanners:
- Dynamic Scan Guidance - Analyzing DAST findings and mapping to source code