Safeguard
Application Security•

ASVS 5.0 V12.3.2: TLS Clients Must Validate Server Certificates

ASVS 5.0 V12.3.2 (Level 2): every TLS client must validate the server certificate. Find and remove verify=False, InsecureSkipVerify and friends.

Safeguard Security Team
3 min read

ASVS 5.0 V12.3.2 requires every TLS client in your system to validate the certificate it receives before talking to the server. That covers chain, expiry, and hostname. It is a Level 2 requirement and applies to code that calls databases, APIs and other services, not only browsers.

Encryption without validation protects against passive listeners and nobody else. An active attacker presents their own certificate and your client accepts it.

Why it matters

Disabled verification is one of the most common findings in code review, usually added during development "to get past a certificate error" and never removed. It turns every outbound call into a man in the middle opportunity.

How to implement it

Use the default behavior of your HTTP client, and trust a custom CA by adding it to the trust store, not by turning checks off.

Python requests:

import requests
r = requests.get("https://api.partner.example/v1/data",
                 timeout=5,
                 verify="/etc/pki/partner-ca.pem")  # or leave default

Node:

const https = require("node:https");
const fs = require("node:fs");
const agent = new https.Agent({ ca: fs.readFileSync("/etc/pki/partner-ca.pem") });
// never set rejectUnauthorized: false

Go: never set InsecureSkipVerify: true in tls.Config. Java: do not install a TrustManager that accepts everything, and do not use HostnameVerifier that returns true.

Also set NODE_TLS_REJECT_UNAUTHORIZED unset or 1 in every environment, since the value 0 silently disables checking process wide.

How to test it

  1. Search the code and configs:
grep -rnE "verify\s*=\s*False|InsecureSkipVerify|rejectUnauthorized\s*:\s*false|NODE_TLS_REJECT_UNAUTHORIZED|CURLOPT_SSL_VERIFYPEER|--insecure|-k " .
  1. Run the client against a test server with an expired certificate, a wrong hostname and a certificate from an unknown CA. Each must produce a connection error.

Tools such as https://badssl.com provide such endpoints for quick checks.

Common mistakes

  • Verifying the chain but not the hostname.
  • A global flag in a base image or CI environment that disables verification for every process.
  • Pinning to a leaf certificate with no rotation plan.

Try it yourself

Run the grep from the testing section across all your repositories, Helm charts and CI configuration. For every hit, ask why it exists. Many are test only and can stay behind a clearly named test flag that cannot be enabled in production builds. The rest need a real fix: install the right CA, correct the hostname or renew an expired certificate.

Then write one integration test per language you use that points the client at a server with a bad certificate and asserts that the call fails. That test protects you from the next developer who sees a certificate error at midnight and reaches for the quick workaround.

Finally, check your base images and CI runners for environment variables that disable verification process wide.

Quick check

Our client uses TLS but with verification off. Is that compliant?

No. V12.3.2 requires the client to validate the certificate before communicating.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.