Cybersecurity / Networking

SSL Certificate Expired Error on curl Command Despite Browser Working

When curl reports an expired certificate but every browser connects to the same site without any warning, the certificate itself almost certainly isn't actually expired — the discrepancy points to something specific about your local curl environment, most commonly an outdated CA certificate bundle or an incorrect system clock.

The Problem

Running a request against an HTTPS endpoint fails with a certificate error:

curl: (60) SSL certificate problem: certificate has expired

curl: (60) server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt

Visiting the exact same URL in any modern browser shows a valid, trusted connection with no warning at all, which strongly suggests the certificate genuinely isn't expired, and the problem is local to your curl environment specifically.

Why It Happens

Browsers and curl use separate certificate validation mechanisms, and several environment-specific issues can cause curl to report a problem that doesn't actually reflect reality:

  • Your system's date and time are genuinely incorrect (common on VMs, containers, or machines that have been suspended/resumed without proper time sync), causing certificate validation to fail since the current date appears to be after the certificate's real expiration, or before its start date
  • The local CA certificate bundle curl uses to validate certificate chains is outdated or corrupted, missing a newer root or intermediate certificate that the site's actual certificate chain depends on — separate from the site's own certificate being expired, this is about your local trust store being out of date
  • An intermediate certificate in the chain (not the leaf certificate itself) genuinely has expired or been replaced, and the specific error message from OpenSSL/curl about the chain doesn't always distinguish clearly between "the site's own leaf certificate expired" versus "an intermediate certificate in the chain has an issue," even though these require different fixes
  • A corporate proxy or firewall performing SSL interception is presenting its own certificate, which genuinely might be expired or misconfigured, independent of the real site's actual certificate

The Fix

First, confirm your system's date and time are actually correct, since this is a surprisingly common and easy-to-overlook cause:

date
# compare against the actual current date/time

If the system clock is wrong, correct it — on Linux systems using NTP synchronization, this can also indicate a broken time sync service that needs its own separate attention beyond just manually setting the date once:

sudo timedatectl set-ntp true
sudo systemctl restart systemd-timesyncd

Update your local CA certificate bundle, since an outdated one can fail to validate a legitimately valid, current certificate chain if it's missing newer intermediate or root certificates:

# Debian/Ubuntu
sudo apt-get update && sudo apt-get install --reinstall ca-certificates

# macOS with Homebrew's curl
brew upgrade curl ca-certificates

Directly inspect the actual certificate chain being presented to understand exactly what curl is seeing, rather than relying only on the summary error message:

openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates

This shows the actual notBefore and notAfter dates for the certificate curl is receiving — comparing these against the current date directly confirms whether the certificate genuinely has an expiration issue, or whether the problem is elsewhere in your validation environment.

If you're behind a corporate network with SSL inspection/interception, confirm whether that's the actual source of the certificate curl sees, by checking the certificate's issuer:

openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -issuer

If the issuer shown is your company's own internal certificate authority rather than a public CA you'd expect for that domain, SSL inspection is confirmed as the actual cause — in that case, the fix involves either working with your IT/security team to correctly install their inspection CA certificate into your local trust store, or requesting the specific domain be excluded from inspection if that's an option in your organization's setup.

Still Not Working?

If the certificate dates and chain genuinely check out as valid, and neither system clock nor CA bundle issues explain the discrepancy, test with an explicit, more recent CA bundle file passed directly to curl, bypassing whatever your system's default bundle location currently contains, to isolate whether the system's default bundle location itself is the specific problem:

curl --cacert /path/to/fresh/cacert.pem https://example.com

A fresh, known-good CA bundle (available for download directly from curl's own project, specifically maintained for exactly this kind of troubleshooting) succeeding where your system's default bundle fails confirms definitively that your system's default CA bundle is the actual root cause, pointing you toward a more thorough reinstall or repair of your system's certificate management rather than continuing to investigate the target site itself.