Safeguard
Developer Tools•

How do you make Node, Python, Java and curl trust a private CA?

Point each runtime at your private CA certificate: NODE_EXTRA_CA_CERTS for Node, REQUESTS_CA_BUNDLE for Python, keytool for Java, cacert for curl.

Safeguard Security Team
3 min read

Give each runtime your private CA's certificate in its own way. Node reads a PEM file named by NODE_EXTRA_CA_CERTS, curl takes a cacert option, Python requests honors REQUESTS_CA_BUNDLE, and Java needs the certificate imported with keytool. Never switch verification off to avoid the work.

The shared idea

A client trusts a server when its certificate chains to a root the client holds. A private CA is not in public trust stores, so you add its root certificate, never its key, to the trust list of every runtime that must connect. Each runtime keeps its own list, which is why one fix rarely covers all of them.

Per runtime

RuntimeHow to trust the CA
Node.jsSet NODE_EXTRA_CA_CERTS to a PEM file
Python requestsSet REQUESTS_CA_BUNDLE or pass a bundle path
JavaImport into a truststore with keytool
curlPass a CA file for one transfer, or set CURL_CA_BUNDLE

Node.js. The documentation says the well known root CAs are extended with the extra certificates in the file, which should hold one or more trusted certificates in PEM format. A missing or malformed file produces a single warning, and errors are otherwise ignored, so check the warning. If your code sets the ca option explicitly on a TLS call, neither the well known nor the extra certificates are used. Newer Node releases can also load the operating system store when you set NODE_USE_SYSTEM_CA, added in v24.6.0 and v22.19.0.

Python. Requests reads REQUESTS_CA_BUNDLE from the environment. One gotcha from its own documentation: when you build requests with a prepared Session flow, environment settings are not merged automatically, and you get a certificate verify failure unless you merge them.

Java. keytool imports a certificate or chain with the importcert command, into a truststore you then point the JVM to.

keytool -importcert -alias corp-root -file corp-root.pem -keystore truststore.p12

curl. Use a CA file for a single transfer, or set CURL_CA_BUNDLE, SSL_CERT_FILE or SSL_CERT_DIR. On some platforms curl can use the native store.

curl --cacert corp-root.pem https://internal.example.com

What not to do

curl's own documentation strongly recommends avoiding the insecure option even for experiments. Node says NODE_TLS_REJECT_UNAUTHORIZED set to 0 disables validation, making TLS insecure, and strongly discourages it. Both leave you open to interception. The safer pattern is in what to do instead of disabling verification.

Make it maintainable

  1. Distribute the CA certificate in one place, such as a base image layer.
  2. Scope the CA with name constraints so a leaked key cannot impersonate public sites. See name constraints for a private CA.
  3. Rotate the CA before it expires and document where it is installed.

Where Safeguard fits

Safeguard scans dependencies and SBOMs for known vulnerabilities, including those in the TLS and crypto libraries your projects pull in, and you can try it with the free scan at gold.safeguard.sh/scan.

Quick check

Should I share the CA's private key with developers?

No. Share the CA certificate, which is public. The key stays offline and protected.

Does NODE_EXTRA_CA_CERTS replace the built in roots?

No. It extends them, unless your code sets the ca option explicitly.

Sources

Last reviewed: 19 October 2026.

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.