OpenSSL "self-signed certificate in certificate chain" in CI
OpenSSL followed the certificate chain to a self-signed root, but that root is not in the trusted store, so it reports verify error 19. This is typical when a corporate TLS-inspecting proxy or an internal CA re-signs traffic: the chain is internally consistent but anchored on a root the runner does not trust yet. The fix is to add that root to the trust store.
What this error means
openssl s_client prints "verify error:num=19:self-signed certificate in certificate chain" and "Verify return code: 19". Node reports the same situation as SELF_SIGNED_CERT_IN_CHAIN.
depth=1 CN = Corp Proxy Root CA
verify error:num=19:self-signed certificate in certificate chain
Verify return code: 19 (self-signed certificate in certificate chain)Common causes
A corporate proxy re-signs TLS with its own root
A MITM proxy presents a chain ending at an internal self-signed root that the runner has not been told to trust.
An internal CA root is not distributed to runners
Your own certificate authority root is missing from the runner store, so its otherwise valid chain fails verification.
How to fix it
Add the internal root to the trust store
- Get the self-signed root certificate in PEM format.
- Copy it into the system CA directory and refresh the store.
- Re-run verification to confirm return code 0.
sudo cp corp-proxy-root.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
openssl s_client -connect example.com:443 -CAfile /etc/ssl/certs/ca-certificates.crtExport the CA bundle to language runtimes
Point Node, Python, and other tools at the same bundle so they trust the proxy root too.
export NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crtHow to prevent it
- Distribute the internal or proxy CA root to all runner images.
- Point every runtime at the same trust bundle via env vars.
- Avoid disabling verification, which hides a genuine substitution.