Claude Code "self signed certificate in certificate chain": NODE_EXTRA_CA_CERTS, CLAUDE_CODE_CERT_STORE and the emSign Block#
Published by Alex Sorokoletov
SELF_SIGNED_CERT_IN_CHAIN means Claude Code reached a server whose root certificate it does not trust. Behind a TLS-inspecting proxy, point NODE_EXTRA_CA_CERTS at a PEM file with the proxy's root. From v2.1.303, the four eMudhra emSign roots are refused in every store, including that file, so hosts chained to them fail on v2.1.303 even with the root added.
Which certificates Claude Code trusts#
Claude Code builds its list of trusted roots from up to three sources:
| Source | Default | What changes it |
|---|---|---|
| Bundled roots (the Mozilla root list that ships with Claude Code) | On | CLAUDE_CODE_CERT_STORE |
| Operating system certificate store | On since v2.1.101 | CLAUDE_CODE_CERT_STORE; NODE_OPTIONS=--use-system-ca or --use-openssl-ca selects only this store |
| Extra PEM file | None | NODE_EXTRA_CA_CERTS |
Expired certificates from the system store are dropped. If the system store cannot be read and the bundled roots are off, Claude Code falls back to the bundled roots.
How to fix it behind a corporate proxy#
Export the proxy's root certificate (or the full chain) as PEM, then start Claude Code with the file:
export NODE_EXTRA_CA_CERTS="$HOME/certs/corporate-root.pem"
claude
Since v2.1.101 a root that IT installed in the operating system store is trusted without this step. If it still fails, check that the system store is on:
CLAUDE_CODE_CERT_STORE=bundled,system claude
CLAUDE_CODE_CERT_STORE takes a comma-separated list of bundled and system. Other values are ignored with a warning, and an empty or all-invalid list means both. CLAUDE_CODE_CERT_STORE=bundled stops trusting the system store.
Client certificates for mutual TLS are separate: CLAUDE_CODE_CLIENT_CERT, CLAUDE_CODE_CLIENT_KEY and CLAUDE_CODE_CLIENT_KEY_PASSPHRASE.
The v2.1.303 emSign deny list#
v2.1.303 (published 2026-10-18) adds a list of root certificates that Claude Code refuses to trust. Its release notes say only "Bug fixes and reliability improvements". The list holds the four eMudhra emSign roots:
| Root | SHA-256 fingerprint |
|---|---|
| emSign Root CA - G1 | 40f6af0346a99aa1cd1d555a4e9cce62c7f9634603ee406615833dc8c8d00367 |
| emSign Root CA - C1 | 125609aa301da0a249b97a8239cb6a34216f44dcac9f3954b14292f2e8c8608f |
| emSign ECC Root CA - G3 | 86a1ecba089c4a8d3bbe2734c612ba341d813e043cf9e8a862cd5c57a36bbe6b |
| emSign ECC Root CA - C3 | bc4d809b15189d78db3e1d8cf4f9726a795da1643ca5f1358e1ddb0edc0d7eb3 |
All four are in Mozilla's root list as of September 2026, and macOS ships G1 and G3. Claude Code removes them from the bundled roots, the system store and the NODE_EXTRA_CA_CERTS file. A certificate is refused when its own fingerprint or its public key matches the list, so a reissued certificate with the same key is also refused.
The effect, checked against www.emsign.com, which chains to emSign Root CA - G1, with an HTTP MCP server pointed at it:
| Version | Result |
|---|---|
| v2.1.302 | TLS succeeds (the server answers with an HTML page) |
| v2.1.303 | SELF_SIGNED_CERT_IN_CHAIN: self signed certificate in certificate chain |
A control host chained to a different root gave the same result on both versions. Commands that Claude Code runs through the Bash tool use the system's own TLS stack and are not affected.
Messages you may see#
A readable emSign root in NODE_EXTRA_CA_CERTS is dropped silently. The rest of the file still loads. Three messages go to the terminal when the root sits in the file in a form Claude Code cannot read:
- "Claude Code ignored a block in the NODE_EXTRA_CA_CERTS file: the block holds a root certificate on the CLI's deny list, in a form Claude Code could not read. The other certificates in the file are still used."
- "Claude Code ignored all of the NODE_EXTRA_CA_CERTS file: it holds a root certificate on the CLI's deny list, in a form Claude Code could not read. Run Claude Code with --debug to write its SHA-256 fingerprint to the debug log, then remove that certificate from the file."
- "Claude Code ignored all of the NODE_EXTRA_CA_CERTS file: it holds root certificates on the CLI's deny list nested too deeply to cut out. Remove them so the rest of the file is used."
The second and third mean your proxy root in the same file is ignored too, so every connection through the proxy fails until you remove the emSign block.
If you need a host chained to emSign#
No setting in v2.1.303 trusts these roots again. Options, from least to most effort:
- Remove emSign roots from your
NODE_EXTRA_CA_CERTSfile if they are there, so the rest of the file keeps working. - Reach the host through a TLS-inspecting proxy whose own root you trust.
- Stay on v2.1.302 until a later release changes the list:
claude install 2.1.302
export DISABLE_AUTOUPDATER=1
How to see what Claude Code loaded#
Run claude --debug and look for the CA certs: lines:
CA certs: stores=bundled,system, extraCertsPath=/Users/you/certs/corporate-root.pem
CA certs: Loaded 121 bundled root certificates
CA certs: Dropped blocked certificate 40f6af03… from bundled
CA certs: Appended extra certificates from NODE_EXTRA_CA_CERTS (/Users/you/certs/corporate-root.pem)
"Nothing from NODE_EXTRA_CA_CERTS is left to append" means the file had only refused or unreadable certificates.
Environment variables#
| Variable | What it does |
|---|---|
NODE_EXTRA_CA_CERTS | Path to a PEM file of extra root certificates to trust, such as a TLS-inspecting proxy's root. From v2.1.303, emSign roots in the file are dropped. |
CLAUDE_CODE_CERT_STORE | Comma-separated CA sources to trust: bundled, system, or both (the default since v2.1.101). Unknown values are ignored with a warning. |
Timeline#
| Version | Published | Change |
|---|---|---|
| v2.1.101 | 2026-04-10 | The operating system store is trusted by default; CLAUDE_CODE_CERT_STORE=bundled turns it off. |
| v2.1.199 | 2026-07-02 | Certificate errors fail at once with a fix hint instead of using up retries. |
| v2.1.273 | 2026-09-15 | Certificate and proxy errors name the error code and the fix, such as NODE_EXTRA_CA_CERTS. |
| v2.1.303 | 2026-10-18 | The four emSign roots are refused in every store. Not in the release notes. |
Should you change anything?#
If you do not use emSign-issued sites or MCP servers, v2.1.303 changes nothing for you. If your NODE_EXTRA_CA_CERTS file was built from a full CA bundle, check it for emSign blocks: a readable one is dropped quietly, but an unreadable one can make Claude Code ignore the whole file, including your proxy root.
FAQ#
Q: How do I fix "self signed certificate in certificate chain" in Claude Code?
A: Set NODE_EXTRA_CA_CERTS to a PEM file that holds your proxy's or server's root certificate, or install that root in the operating system store, which Claude Code trusts by default since v2.1.101.
Q: Does Claude Code use the macOS Keychain or Windows certificate store?
A: Yes. Since v2.1.101 it trusts the operating system store together with its bundled roots. CLAUDE_CODE_CERT_STORE=bundled turns the system store off.
Q: Why does a site with an emSign certificate fail after updating Claude Code?
A: v2.1.303 refuses the four eMudhra emSign roots in the bundled list, the system store and NODE_EXTRA_CA_CERTS. Hosts chained to them fail with SELF_SIGNED_CERT_IN_CHAIN on v2.1.303.
Q: Can I add the emSign root to NODE_EXTRA_CA_CERTS to fix it?
A: No. Claude Code drops emSign roots from that file too. Staying on v2.1.302 with DISABLE_AUTOUPDATER=1 is the only way to keep reaching those hosts directly.
Q: What values does CLAUDE_CODE_CERT_STORE take?
A: bundled, system, or both, comma-separated. The default is both.
Sources: Claude Code changelog, v2.1.101, v2.1.199, v2.1.273 and v2.1.303 | Mozilla CA bundle as of September 25, 2026 (curl.se)
Related: CLAUDE_CODE_CERT_STORE in the env-var glossary | Claude Code v2.1.303 analysis | CLAUDE_CODE_ATTRIBUTION_HEADER Guide