DEV Community

Tianhao Zhou
Tianhao Zhou

Posted on

When npm install Fails with SELF_SIGNED_CERT_IN_CHAIN in Corporate Networks (Zscaler + Node 22 Deep Dive)

🚨 The Problem

Suddenly, npm install started failing across all projects with:

SELF_SIGNED_CERT_IN_CHAIN
Enter fullscreen mode Exit fullscreen mode

It wasn’t repo-specific.
It wasn’t npm registry downtime.
It wasn’t a corrupt cache.

It happened everywhere.

Environment:

  • Node.js v22.x
  • npm v10.x
  • Corporate network (Zscaler SSL Inspection)
  • Windows + Git Bash

πŸ” What Was Really Happening?

Our company uses Zscaler SSL Inspection, which performs TLS interception (MITM) for outbound HTTPS traffic.

So instead of the normal TLS chain:

registry.npmjs.org
    ↑
Public CA
Enter fullscreen mode Exit fullscreen mode

The actual chain becomes:

registry.npmjs.org (re-signed)
    ↑
Zscaler Intermediate
    ↑
Internal Enterprise CA
    ↑
Enterprise Root CA
Enter fullscreen mode Exit fullscreen mode

This is normal in enterprise environments.


❓ Why Did It Suddenly Break?

The key trigger was:

Node.js v22 tightened TLS validation behavior.

Older Node versions were more tolerant about incomplete chains.

Node 22:

  • Uses OpenSSL 3.x
  • Enforces stricter certificate validation
  • Does not auto-reconstruct incomplete intermediate chains

Providing only the enterprise root certificate is no longer sufficient.


πŸ”¬ How I Diagnosed It

First, I checked whether my local CA file contained a full chain:

grep -c "BEGIN CERTIFICATE" zscaler-root.cer
Enter fullscreen mode Exit fullscreen mode

Result:

1
Enter fullscreen mode Exit fullscreen mode

Only one certificate.

But when I inspected the live TLS connection:

openssl s_client -showcerts -connect registry.npmjs.org:443 \
  -servername registry.npmjs.org < /dev/null > /tmp/npm-chain.txt
Enter fullscreen mode Exit fullscreen mode

Then:

grep -c "BEGIN CERTIFICATE" /tmp/npm-chain.txt
Enter fullscreen mode Exit fullscreen mode

Result:

5
Enter fullscreen mode Exit fullscreen mode

Five certificates were involved in the trust chain.

That was the smoking gun.


πŸ›  The Real Fix: Use the Full Certificate Chain

Step 1 – Split certificates

awk '/BEGIN CERTIFICATE/{i++} {print > ("/c/certs/npm-chain-" i ".pem")}' /tmp/npm-chain.txt
Enter fullscreen mode Exit fullscreen mode

Step 2 – Combine into a full bundle

cat /c/certs/npm-chain-1.pem \
    /c/certs/npm-chain-2.pem \
    /c/certs/npm-chain-3.pem \
    /c/certs/npm-chain-4.pem \
    /c/certs/npm-chain-5.pem \
    > /c/certs/npm-full-chain.pem
Enter fullscreen mode Exit fullscreen mode

Verify:

grep -c "BEGIN CERTIFICATE" /c/certs/npm-full-chain.pem
Enter fullscreen mode Exit fullscreen mode

Step 3 – Configure npm and Node

npm config set cafile "C:\\certs\\npm-full-chain.pem"
export NODE_EXTRA_CA_CERTS=/c/certs/npm-full-chain.pem
npm cache clean --force
Enter fullscreen mode Exit fullscreen mode

Then:

npm install
Enter fullscreen mode Exit fullscreen mode

Success.


🧠 Why This Works

Node validates certificate chains strictly.

When behind corporate SSL inspection:

  • The leaf certificate is re-issued by Zscaler.
  • Multiple internal CA layers are involved.
  • Node must see the entire chain to validate trust.

If any intermediate is missing:

SELF_SIGNED_CERT_IN_CHAIN
Enter fullscreen mode Exit fullscreen mode

Providing only the root CA is not enough in multi-level PKI environments.


πŸ’‘ Why Browsers Worked

Browsers use the Windows certificate store.

Node does not (by default).

So:

  • Windows trusts enterprise root CA
  • Browser succeeds
  • Node fails

Different trust stores = different behavior.


🏒 Lessons for Enterprise Environments

If you're behind:

  • Zscaler
  • Blue Coat
  • Palo Alto SSL Inspection
  • Any corporate TLS interception

And using:

  • Node 20+
  • Node 22+
  • npm 10+

You may need to provide a full certificate bundle, not just a root certificate.


πŸ”₯ Key Takeaway

The error wasn't really about npm.

It was about:

Enterprise TLS inspection + multi-level internal PKI + stricter Node.js TLS validation.

Once you understand the trust chain, the fix becomes straightforward.


πŸš€ Final Thought

If you see:

SELF_SIGNED_CERT_IN_CHAIN
Enter fullscreen mode Exit fullscreen mode

In a corporate environment, don’t disable SSL verification.

Instead:

  1. Inspect the live TLS chain
  2. Extract all certificates
  3. Provide a complete CA bundle to Node

Security preserved. Problem solved.


If you found this helpful, let me know.
Enterprise TLS debugging is painful β€” but very educational.

Top comments (0)