Join our Newsletter — 33% off our NHI Course
Home› Guides› x509 Certificate Signed by Unknown Authority Troubleshooting Guide:…
Guide Secrets Management

x509 Certificate Signed by Unknown Authority Troubleshooting Guide: Find the Missing Trust Anchor and Fix It Safely

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 11 November 2026 15 min read
On this page

"x509: certificate signed by unknown authority" means a client could not build a chain from the server's certificate to any root it trusts, and the fastest "fix" engineers reach for, turning verification off, removes the only check that stops an interception attack. The error comes from Go's crypto/x509 package, so it appears in Docker, Kubernetes tooling, Terraform, Helm, Vault clients and most cloud-native software; OpenSSL, curl, Python, Node.js and Java report the same failure with different words. This guide maps those messages to their causes, shows how to diagnose each one with standard tools, and gives the correct fix for each runtime without weakening trust. It is for platform, DevOps and security engineers who run internal PKI, TLS inspection proxies or private registries. Error strings were checked against the Go, OpenSSL, Node.js, curl, Python and OpenJDK source and documentation on 11 November 2026.

Key takeaways

  • The error is about the chain, not the leaf. The client found the server's certificate but could not link it to a trust anchor in its own store: either the root is missing on the client or the server did not send the intermediate.
  • Find out whose trust store is used. Go, Node.js, Python, Java and curl can each read a different store on the same host. Adding a root to the operating system does nothing for a JVM using its own cacerts or a container built from a slim base image.
  • Fix the server first when the intermediate is missing. If openssl s_client -showcerts shows only one certificate, the server configuration is wrong and every client will need a workaround until it is fixed.
  • Never ship InsecureSkipVerify, -k or verify=False. Add the specific private root to the specific trust store instead, and scope it to the workload that needs it.
  • Corporate TLS inspection is the most common hidden cause. A proxy re-signs traffic with a private root that laptops trust through policy but containers, CI runners and language runtimes do not.

What the error actually means

When a TLS client receives a server certificate it tries to build a path: leaf, then each issuing intermediate, up to a self-signed root that is present in its trust store. In Go, UnknownAuthorityError is returned "when the certificate issuer is unknown", and its message is exactly x509: certificate signed by unknown authority. Since Go wraps verification failures inside TLS, a modern Go client usually prints tls: failed to verify certificate: x509: certificate signed by unknown authority. When Go found a candidate issuer but rejected it, it appends a hint in the form (possibly because of "..." while trying to verify candidate authority certificate "..."). That hint is valuable: it often names the exact root or intermediate that was considered and the reason, such as an unsupported signature algorithm.

The error is distinct from its neighbours. x509: certificate has expired or is not yet valid is a time problem (see the Expired Certificate Outage Troubleshooting Guide). x509: certificate is valid for ..., not ... is a name mismatch. x509: certificate relies on legacy Common Name field, use SANs instead means the certificate has no Subject Alternative Name. x509: failed to load system roots and no roots provided means the client had no trust store at all, which is common in scratch or distroless containers. Fixing the wrong one wastes hours, so read the full string first.

The same failure in every runtime

Each TLS stack reports an untrusted chain differently. The table maps the strings you will see to the underlying condition. OpenSSL reason strings are taken from OpenSSL's x509_txt.c; Node.js codes from its TLS documentation.

Runtime or toolMessage or codeUsual meaning
Go (Docker, kubectl, Helm, Terraform)x509: certificate signed by unknown authorityNo path to a trusted root
OpenSSL (code 20)unable to get local issuer certificateIssuer of the top certificate received is not in the local store
OpenSSL (code 21)unable to verify the first certificateServer sent only the leaf and the intermediate is unavailable
OpenSSL (code 2)unable to get issuer certificateAn issuer in the middle of the chain could not be found
OpenSSL (code 18)self-signed certificateThe leaf is self-signed and not trusted
OpenSSL (code 19)self-signed certificate in certificate chainChain ends in a root the client does not trust (classic TLS inspection symptom)
curl (exit 60, CURLE_PEER_FAILED_VERIFICATION)SSL certificate problem: followed by the OpenSSL reasonSame as the OpenSSL reason that follows
Node.jsUNABLE_TO_GET_ISSUER_CERT_LOCALLY, UNABLE_TO_VERIFY_LEAF_SIGNATURE, SELF_SIGNED_CERT_IN_CHAIN, DEPTH_ZERO_SELF_SIGNED_CERTMirror the OpenSSL codes above
Python sslSSLCertVerificationError with reason CERTIFICATE_VERIFY_FAILEDThe verify_message attribute holds the OpenSSL reason
Java (JSSE)PKIX path building failed: followed by the underlying exceptionNo path from the leaf to an entry in the JVM truststore
Chromium browsersERR_CERT_AUTHORITY_INVALID (net error -202)Root not trusted by the platform verifier

Likely causes, most to least common

  1. Private or internal CA not in the client's store: the service uses a certificate from an enterprise CA, a Kubernetes cluster CA or a service mesh, and the client only trusts public roots. See the Enterprise PKI Design and CA Hierarchy Guide.
  2. TLS inspection proxy: a secure web gateway or firewall decrypts outbound traffic and re-signs it with its own root. Managed laptops trust it through Group Policy or MDM; containers, WSL, CI runners and bundled language stores do not. See the TLS Inspection Guide.
  3. Server does not send the intermediate: the web server, load balancer or ingress is configured with the leaf only. Browsers often hide this by fetching or caching intermediates, so the site "works in Chrome" while curl and Go fail.
  4. Minimal container image without a CA bundle: scratch, some distroless and some Alpine-based images have no ca-certificates package or an outdated one.
  5. Application-specific trust store: the JVM uses cacerts, Node.js uses its bundled Mozilla roots by default, Python packages may use their own bundle, and a ca option in code replaces the defaults entirely.
  6. Root rotation or distrust: a CA moved to a new root, a cross-signed chain changed, or a root was removed from a root programme, and old clients do not have the new anchor. See the CA Compromise and Mass Certificate Replacement Playbook.
  7. Genuine interception: an attacker-in-the-middle presenting a certificate from an untrusted CA. This is the case the check exists for, and it is why the error must never be suppressed.

How to diagnose it

Work from the outside in: what the server sends, then what the client trusts, then which store the failing process actually reads.

  1. Capture what the server presents: run openssl s_client -connect host:443 -servername host -showcerts. OpenSSL sends SNI by default from the host given, but set -servername explicitly when connecting by IP. -showcerts prints the certificates in the order the server sent them; the output is not a verified chain. One certificate block means the intermediate is missing.
  2. Read the issuer and subject of each block: the issuer of each certificate should equal the subject of the next. The last issuer named is the root the client must hold. A root such as a vendor proxy name, "Corporate Root" or a cluster CA tells you the cause immediately.
  3. Verify against a known store: save the chain and run openssl verify -CAfile root.pem -untrusted intermediates.pem leaf.pem. -untrusted supplies intermediates that may be used to build the path without being trusted. If this succeeds with the right root, the server chain is fine and the problem is the client store.
  4. Repeat from where the failure happens: run the same check from inside the container, pod or CI job, not from your laptop. A different egress path (proxy, NAT, service mesh sidecar) can mean a different certificate.
  5. Identify the store the process uses: for Python, ssl.get_default_verify_paths() returns the resolved cafile and capath and the OpenSSL environment variables that override them. For Go on Linux, check SSL_CERT_FILE and SSL_CERT_DIR. For Java, check javax.net.ssl.trustStore; the JDK otherwise uses jssecacerts if present, then cacerts. For Node.js, check NODE_EXTRA_CA_CERTS and whether code passes a ca option.
  6. Read Go's hint: if the message includes "possibly because of", the named candidate certificate was found but rejected, which points to a signature algorithm, key usage or constraint problem in your CA rather than a missing root.

The OpenSSL for Security Teams guide covers the inspection commands in more depth, and the Certificate and Key File Formats guide explains PEM, DER and PKCS#12 conversions you may need along the way.

Fixes by runtime and platform

The correct fix is always to make the right anchor available to the right client, or to make the server send a complete chain. The table lists the documented mechanism for each platform.

WhereDocumented mechanismNotes
Debian, UbuntuCopy the root to /usr/local/share/ca-certificates/ and run update-ca-certificatesThe file must have a .crt extension; output goes to /etc/ssl/certs/ca-certificates.crt
RHEL 9 and derivativesCopy to /etc/pki/ca-trust/source/anchors/ and run update-ca-trust extractCheck with trust list; trust anchor adds or removes directly
Go programs on LinuxSystem store, or SSL_CERT_FILE / SSL_CERT_DIROn macOS and Windows, Go uses the platform verifier; setting these variables there disables it unless GODEBUG=x509sslcertoverrideplatform=0
Docker Engine pulling from a registryPlace the CA as ca.crt in /etc/docker/certs.d/<host:port>/Rootless: ~/.config/docker/certs.d; Docker Desktop: ~/.docker/certs.d on the host
Node.jsNODE_EXTRA_CA_CERTS=/path/root.pem, or --use-system-ca / NODE_USE_SYSTEM_CA=1Read only at process start; ignored when code sets ca explicitly
PythonSystem store via OpenSSL defaults, or SSL_CERT_FILELibraries with their own bundle need their own setting; check each library's documentation
Javakeytool -importcert -cacerts -alias corp-root -file root.pem, or a dedicated truststore via javax.net.ssl.trustStoreEach JDK installation has its own cacerts; image rebuilds replace it
curl--cacert, CURL_CA_BUNDLE, or --ca-native for the OS storecurl's documentation says never skip verification in production
kubectlcertificate-authority-data in the kubeconfig cluster entryA stale kubeconfig after cluster CA rotation produces this exact error
Server sideConfigure the full chain (leaf then intermediates) on the listenerRFC 8446 lets the root be omitted, but each certificate should certify the one before it

Containers: bake the private root into the image at build time (install ca-certificates, copy the root, run the distro update command) rather than mounting it ad hoc, so every replica behaves the same. For Kubernetes at scale, distribute the bundle as a ConfigMap and mount it at the path the runtime reads. The Certificate trust stores and root CA management guide covers trust store design; this guide stays with the incident.

Server chain: when the intermediate is missing, the fix belongs on the server. TLS 1.3 (RFC 8446, section 4.4.2) requires the sender's certificate first, says each following certificate should directly certify the one before it, and allows a trust anchor to be omitted when peers are known to have it. Serve leaf plus intermediates; do not serve the root.

Unsafe workarounds and safer equivalents

Tempting workaroundWhy it is dangerousSafer equivalent
InsecureSkipVerify: true (Go), verify=False (Python), NODE_TLS_REJECT_UNAUTHORIZED=0 (Node.js), curl -kAccepts any certificate from anyone, including an attacker on the path; usually outlives the incidentSupply the specific root with the runtime's CA option
Docker insecure-registriesDisables verification for that registry, letting image pulls be tampered with/etc/docker/certs.d/<host>/ca.crt
Trusting the leaf certificate directlyBreaks at every renewal and hides the real chain problemTrust the issuing root, fix the server chain
Adding the root to every image and host globallyA private root can then vouch for any public name everywhereScope it to the workloads that need it, and constrain the CA where your PKI supports name constraints
Disabling verification in a client library defaultSilently affects every outbound call from that servicePer-connection trust configuration, reviewed in code review

Treat any verification bypass found in code or configuration as a security defect. Adding a root certificate is itself a technique adversaries use (MITRE ATT&CK T1553.004 Install Root Certificate), so root additions should be change-controlled and monitored, not done ad hoc during an outage.

Decision guidance

  • One service, internal CA: add the internal root to that service's image or runtime trust configuration. Do not touch the host store if the host serves other tenants.
  • Whole estate behind TLS inspection: distribute the proxy root centrally (base images, golden AMIs, CI runner images, developer tooling) and keep an exception list for destinations that must not be inspected, such as certificate-pinned services and authentication endpoints. Pinned clients fail under inspection by design; see the Certificate Pinning guide.
  • Public endpoint failing only for some clients: suspect a missing intermediate or a root change, fix the server chain, and check client root store age.
  • Small organisation: prefer publicly trusted certificates via ACME for anything reachable by third parties, and reserve private roots for genuinely internal traffic.
  • Large organisation: publish one supported CA bundle per platform with an owner and a version, and make "uses the standard bundle" a deployment check.

Where identity fits

A trust anchor is an identity decision: every certificate it signs becomes a trusted identity for every client that holds it. Service-to-service calls, mTLS between workloads and agents calling internal APIs all rely on the client trusting the right issuer and only that issuer. When an engineer disables verification to unblock a pipeline, the workload credentials sent over that connection (API keys, bearer tokens, client certificates) become exposed to whoever answers. See the mTLS Guide and the Machine Identity, PKI and Certificate Lifecycle Guide.

Detection and measurement

  • Code and config scanning: search repositories and infrastructure code for InsecureSkipVerify, verify=False, NODE_TLS_REJECT_UNAUTHORIZED, -k/--insecure in scripts and insecure-registries in Docker daemon configuration.
  • Trust store change monitoring: alert on changes under /usr/local/share/ca-certificates, /etc/pki/ca-trust/source/anchors, JVM cacerts files and the Windows Trusted Root Certification Authorities store.
  • Chain completeness checks: probe every TLS listener and record the number of certificates served; one certificate from a publicly trusted endpoint is a defect.
  • Metrics: verification bypasses found in code (target zero); percentage of images built from a base with the standard CA bundle; listeners serving an incomplete chain; mean time to resolve unknown authority incidents; number of private roots in use, each with a named owner.

Framework mapping

FrameworkReferenceRelevance
NIST SP 800-53 Rev. 5SC-8 Transmission Confidentiality and Integrity; SC-17 Public Key Infrastructure Certificates; SC-23 Session Authenticity; CM-6 Configuration SettingsVerified TLS, managed trust anchors, no verification bypass in configuration
NIST CSF 2.0PR.DS-02; PR.AA-03; PR.PS-01Data in transit protected, services authenticated, configuration managed
CIS Controls v8.13.10 Encrypt Sensitive Data in TransitEncryption only protects if the peer is verified
ISO/IEC 27001:2022 Annex AA.8.24 Use of cryptography; A.8.20 Networks securityRules for certificate and key use, network protection
MITRE ATT&CKT1553.004 Install Root Certificate; T1557 Adversary-in-the-MiddleWhy root additions are monitored and verification is never disabled
MITRE D3FENDD3-CA Certificate AnalysisInspecting certificates and chains as a defensive control

Common failure patterns

  • "Works on my laptop": the laptop trusts the inspection proxy root through device policy; the container on the same laptop does not. Diagnose from inside the failing process.
  • Temporary -k that became permanent: a bypass added during an incident stays in a deployment script for years, quietly accepting any certificate.
  • Root added to the wrong store: the OS store is updated but the JVM, Node.js or a Python library uses its own, so nothing changes and engineers conclude the root is wrong.
  • Leaf-only server configuration: browsers paper over it, so it ships; every API client and SDK then fails.
  • Stale kubeconfig after cluster CA rotation: CI jobs carry an old certificate-authority-data and fail with unknown authority.
  • Explicit ca option replacing defaults: code that sets a custom CA in Node.js or Go loses the public roots, so calls to public APIs start failing.

Practitioner checklist

  • Read the full error string and confirm it is an unknown authority error, not expiry or name mismatch.
  • Run openssl s_client -showcerts with the correct -servername from inside the failing environment.
  • Confirm the server sends leaf plus intermediates; fix the listener if not.
  • Identify the root at the top of the chain and whether it is public, internal or an inspection proxy.
  • Find the trust store the failing process actually reads and add the root there, scoped to that workload.
  • Bake private roots into base images and CI runner images rather than patching running containers.
  • Remove any verification bypass introduced during the incident and scan code for others.
  • Put trust store changes under change control and alert on unexpected root additions.

Standards and references

Related NHI Mgmt Group resources: Certificate trust stores and root CA management · TLS Handshake Failure Troubleshooting Guide · TLS Inspection Guide · Enterprise PKI Design and CA Hierarchy Guide

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 11 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org