Describe the bug
GitHub Copilot CLI's CA loader calls tls.getCACertificates("system") on every invocation in addition to "bundled" and "extra". On macOS, that call iterates every keychain cert and invokes SecTrustEvaluateWithError synchronously via XPC to trustd — which (because of a Node bug, see References) uses a revocation-enabled trust policy and triggers OCSP/CRL fetches per cert. On machines with any network-flow filter (corporate NetworkExtension, ZeroTier, etc.), each fetch pays a per-flow cost and totals 5-10 seconds of latency on every CLI invocation — even sub-commands like --version that don't make HTTPS requests inherit the cost because the call happens during SEA startup.
The "system" arg is also functionally redundant with "bundled" for *.github.com / *.githubcopilot.com endpoints. See related #869 (which reports a separate failure caused by the duplicate-certs concatenation from this same code).
Affected version
GitHub Copilot CLI 1.0.48 (also reproduced on 1.0.39). macOS 26.4.1, Apple Silicon. Node 24.15.0 inside the SEA.
Steps to reproduce the behavior
$ time copilot --allow-all-tools -p "reply with exactly: ack"
ack
real 0m12.43s
user 0m1.98s
sys 0m0.17s
Wall-clock vs user CPU mismatch confirms it's I/O wait, not CPU work. sample(1) on the grandchild SEA process during the wait:
node::crypto::GetSystemCACertificates
node::crypto::ReadMacOSKeychainCertificates
node::crypto::IsCertificateTrustedForPolicy
node::crypto::IsCertificateTrustValid
SecTrustEvaluateWithError
SecTrustEvaluateIfNecessary
securityd_send_sync_and_do ← synchronous XPC to trustd
xpc_connection_send_message_with_reply_sync
mach_msg2_trap
Isolated reproduction with standalone Node 24 on the same machine:
$ node -e 'const t0=process.hrtime.bigint();
require("tls").getCACertificates("system");
console.log(`${(Number(process.hrtime.bigint()-t0)/1e6).toFixed(0)}ms`)'
5287ms
$ node -e 'const t0=process.hrtime.bigint();
require("tls").getCACertificates("bundled");
console.log(`${(Number(process.hrtime.bigint()-t0)/1e6).toFixed(0)}ms`)'
0.1ms
HTTPS request to api.github.com:
- default (bundled): 53ms
node --use-bundled-ca …: 103ms
node --use-system-ca …: 5093ms — 96× slower
Expected behavior
CLI startup should not pay multi-second latency for a CA loader that produces certs equivalent to the bundled Mozilla store.
Root cause in copilot-cli source
Decoded from app.js (npm-loader fallback; the SEA's bundled JS contains the same logic):
function buildCAList() {
const envCerts = ["NODE_EXTRA_CA_CERTS","SSL_CERT_FILE","CURL_CA_BUNDLE"].flatMap(readEnvCAFile);
return typeof tls.getCACertificates === "function"
? [...envCerts,
...tls.getCACertificates(), // default (bundled in Node 24+)
...tls.getCACertificates("system"), // ← THIS LINE
...tls.getCACertificates("bundled"), // bundled (already implied above)
...tls.getCACertificates("extra")]
: [...envCerts, ...tls.rootCertificates];
}
Proposed fix
Remove the tls.getCACertificates("system") line. One-line patch. If retaining the option for users with private CAs is desired, gate it behind a COPILOT_USE_SYSTEM_CA=1 env var defaulting OFF. The current always-on cost is borne by every macOS user even when they don't need it. This also resolves the duplicate-certs issue tracked at #869.
Why this user sees the upper end
My login keychain had 1589 certs (mostly auto-imported S/MIME contact certs from Mail.app over 20 years). After pruning 1478 long-expired certs, the call dropped from ~10s to ~5s — the floor on this machine, set by ~270 still-valid certs each costing ~20 ms in SecTrustEvaluateWithError. ZeroTier's feth1960 virtual interface and zerotier-one daemon further amplify per-flow cost for the trustd OCSP traffic.
Users without a flow filter and a smaller keychain see a smaller version of this same tax (1-2s baseline, per anthropics/claude-code#53660's measurements).
Related
Describe the bug
GitHub Copilot CLI's CA loader calls
tls.getCACertificates("system")on every invocation in addition to"bundled"and"extra". On macOS, that call iterates every keychain cert and invokesSecTrustEvaluateWithErrorsynchronously via XPC totrustd— which (because of a Node bug, see References) uses a revocation-enabled trust policy and triggers OCSP/CRL fetches per cert. On machines with any network-flow filter (corporate NetworkExtension, ZeroTier, etc.), each fetch pays a per-flow cost and totals 5-10 seconds of latency on every CLI invocation — even sub-commands like--versionthat don't make HTTPS requests inherit the cost because the call happens during SEA startup.The
"system"arg is also functionally redundant with"bundled"for*.github.com/*.githubcopilot.comendpoints. See related #869 (which reports a separate failure caused by the duplicate-certs concatenation from this same code).Affected version
GitHub Copilot CLI 1.0.48 (also reproduced on 1.0.39). macOS 26.4.1, Apple Silicon. Node 24.15.0 inside the SEA.
Steps to reproduce the behavior
Wall-clock vs user CPU mismatch confirms it's I/O wait, not CPU work.
sample(1)on the grandchild SEA process during the wait:Isolated reproduction with standalone Node 24 on the same machine:
HTTPS request to
api.github.com:node --use-bundled-ca …: 103msnode --use-system-ca …: 5093ms — 96× slowerExpected behavior
CLI startup should not pay multi-second latency for a CA loader that produces certs equivalent to the bundled Mozilla store.
Root cause in copilot-cli source
Decoded from
app.js(npm-loader fallback; the SEA's bundled JS contains the same logic):Proposed fix
Remove the
tls.getCACertificates("system")line. One-line patch. If retaining the option for users with private CAs is desired, gate it behind aCOPILOT_USE_SYSTEM_CA=1env var defaulting OFF. The current always-on cost is borne by every macOS user even when they don't need it. This also resolves the duplicate-certs issue tracked at #869.Why this user sees the upper end
My login keychain had 1589 certs (mostly auto-imported S/MIME contact certs from Mail.app over 20 years). After pruning 1478 long-expired certs, the call dropped from ~10s to ~5s — the floor on this machine, set by ~270 still-valid certs each costing ~20 ms in
SecTrustEvaluateWithError. ZeroTier'sfeth1960virtual interface andzerotier-onedaemon further amplify per-flow cost for the trustd OCSP traffic.Users without a flow filter and a smaller keychain see a smaller version of this same tax (1-2s baseline, per anthropics/claude-code#53660's measurements).
Related
tls.getCACertificates("system")blocks startup ~9-10s on corporate-managed Macs (regression in 2.1.119) anthropics/claude-code#53660 — same Node-side root cause analyzed in detail (revocation-enabled trust policy inSecTrustEvaluateWithError). Their workaround was to ship aCLAUDE_CODE_CERT_STORE=bundledenv var users can set.bundled + systemconcatenation causeFailed to list available modelsfor some users.