CWE-296: Improper Following of a Certificate's Chain of Trust
Overview
Improper following of a certificate's chain of trust 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, incomplete chains, or chains with invalid intermediate CA certificates 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, incorrect trust store configuration, or pinning logic that pins a certificate before validating the complete chain.
Relationship to Other CWEs
- CWE-296 (this page) - the chain: the certificate does not chain to a trusted root, whether it is self-signed, signed by an untrusted CA, or missing a valid intermediate.
- CWE-295 (Improper Certificate Validation) - the parent MITRE records for this page and for the other certificate checks listed here. Use it when validation is switched off wholesale rather than failing one specific check; the language-specific pages live there.
- CWE-297 (Improper Validation of Certificate with Host Mismatch) - the name: the chain is valid but nothing checks that the certificate identifies the host being connected to. Chain and name are separate checks, and a client can pass one while failing the other.
- CWE-298 (Improper Validation of Certificate Expiration) - the dates: the certificate is accepted outside the validity window its issuer set.
- CWE-299 (Improper Check for Certificate Revocation) - revocation: the chain is valid and the certificate is in date, but the issuer has withdrawn it since.
OWASP Classification
A04:2025 - Cryptographic Failures
Risk
High: An attacker already on the network path presents a certificate the client accepts without a valid chain, and the TLS session then protects nothing: credentials and session tokens sent over it are readable, and injected responses are indistinguishable from the real server's. That network position is the precondition - public Wi-Fi, a compromised network, or control of DNS or routing.
Remediation Steps
Core Principle: Always validate the complete certificate trust chain to a known trusted root CA or explicitly configured trust anchor; do not disable certificate validation or trust unverified certificates in application code.
Enable Full Certificate Chain Validation
Confirm the TLS/SSL library validates:
- Certificate chains to a trusted root CA
- Certificate is not self-signed unless it is the trusted root or an explicitly configured trust anchor
- Intermediate certificates are included and valid
- Intermediate CA certificates have appropriate Basic Constraints and key usage
- Certificate has not expired
- Certificate revocation status is checked when required by your client stack, PKI, or policy
Use Proper TLS Configuration
Every mainstream HTTP client validates the chain by default, so the fix is almost always the removal of an option that switched validation off, not the addition of new code. The flag has a different name in each ecosystem - a verify parameter, a reject-unauthorized option, a permissive trust manager, a callback that returns true unconditionally - and CWE-295 carries the concrete form for Python, JavaScript, Java, C# and Go.
Two cases specific to chain of trust rather than validation in general:
- Supplying a custom CA replaces the default trust store in most clients rather than adding to it. Internal services then work while every public host fails, and the usual response is to disable validation entirely. Include the platform defaults alongside your CA.
- Pinning before validating is not pinning. A pin check that runs first is comparing the pinned hash against some certificate in the presented chain, not against a verified leaf. An attacker attaches the pinned CA or intermediate to a chain terminating in a leaf of their own: the pin matches the certificate it was taken from, and nothing ever verifies the signatures tying that certificate to the leaf the connection actually uses. Validate the chain, then pin the verified leaf.
Pin Public Keys for Critical Connections (Advanced)
Pin expected public key/SPKI hashes only after the normal chain and hostname validation succeeds. Keep backup pins and a rotation process.
Use the Runtime's Default Trust Store
Rely on the trust store the runtime already uses rather than assembling one:
- Python:
ssl.create_default_context(), which loads the OS store;requestsuses thecertifibundle instead - Node.js: a bundled copy of the Mozilla root list, extended with
NODE_EXTRA_CA_CERTSor a carefully scopedcaoption for internal clients - Java: the JDK's own
cacertskeystore - .NET: the trust store of whichever operating system it is running on - the Windows certificate store, OpenSSL's CA bundle on Linux, the Keychain on macOS
None of these is guaranteed to be the machine's CA store, and whether adding a CA there reaches cacerts or Node's bundled list is a packaging question rather than a language one - so add the CA, then make one request from the runtime itself. CWE-295 has the detail; the mismatch is a routine reason validation was switched off in the first place.
Test Certificate Validation
Verify your implementation rejects invalid certificates and still accepts valid ones:
# Baseline: a valid public certificate must still connect
curl https://badssl.com/ # expect: 200
# 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/
The baseline is the test that matters most for this CWE, because the fix here is
often a custom CA - and a custom CA that replaces the default trust store instead
of adding to it passes all three rejection tests while breaking every public
endpoint. Run all four through the application's own HTTP client as well as
curl, so the code path that carried the finding is the one exercised.