## TL;DR

curl exit 60 means curl could not verify the server's certificate chain against its local trust store. The fix is to give curl a current CA bundle: update your system's CA certificates, point curl at a fresh bundle with --cacert or the CURL_CA_BUNDLE variable, or install your organization's root CA if a corporate proxy re-signs TLS. The -k flag silences the error but is a diagnostic only, never the fix.

### Verbatim error

```text
curl: (60) SSL certificate problem: unable to get local issuer certificate
```

## When this applies

- Any `curl https://...` exits with code 60.
- Scripts or agents running in minimal containers or images that never installed CA certificates.
- Behind a corporate proxy that intercepts and re-signs TLS traffic; the proxy's signing CA is not in the trust store.
- Old OS or curl installs whose root store expired (the September 2021 DST Root CA X3 expiry broke a wave of clients).
- WordPress/PHP installations reporting "Update Failed: Download failed. cURL error 60" (same error, PHP's cURL layer).

## When this does NOT apply

- curl exit 35 (SSL connect error): a TLS handshake or cipher mismatch, not a trust-store problem.
- curl exit 51 with a pinned certificate fingerprint that mismatches: the pin is wrong, not the bundle.
- Browser-only errors like NET::ERR_CERT_DATE_INVALID or an expired domain certificate: those are about the server's own cert, fixed server-side.
- Only one specific host fails while every other HTTPS host works: the server is probably not sending its intermediate certificates. That is a server-side chain problem; error 60 is just what the client sees.

## Fix

### 1. Reproduce and see what curl trusts

```bash
curl -v https://example.com
```

Expected output: the same `curl: (60)` line near the end. `curl --version` also prints the default CA bundle path curl was built with, which tells you where it is looking.

### 2. Update the system CA store

Debian/Ubuntu:

```bash
sudo apt-get update && sudo apt-get install -y ca-certificates
sudo update-ca-certificates
```

Expected output: `Updating certificates in /etc/ssl/certs... 1 added, 0 removed; done.` Re-run your curl command; error 60 should be gone.

RHEL/Fedora:

```bash
sudo dnf reinstall -y ca-certificates
sudo update-ca-trust
```

Expected output: no errors, then `update-ca-trust` prints nothing on success. Re-run curl.

Alpine and other minimal images:

```bash
apk add --no-cache ca-certificates
```

Expected output: the package installs without errors.

### 3. Point curl at a fresh bundle explicitly

If you cannot touch the system store, download the current Mozilla bundle from https://curl.se/docs/caextract.html and use it directly:

```bash
curl --cacert [path to your downloaded cacert.pem] https://example.com
```

Expected output: the request succeeds (HTTP 200) with no certificate error. To make it stick for the session:

```bash
export CURL_CA_BUNDLE=[path to your downloaded cacert.pem]
```

Expected output: subsequent plain `curl https://example.com` calls succeed without --cacert.

### 4. Corporate MITM proxy: install the organization's root CA

Get your org's root CA certificate from your internal IT page. On Debian/Ubuntu, copy it into the system store and refresh:

```bash
sudo cp [org-root-ca].crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
```

Expected output: `1 added, 0 removed; done.` If you cannot modify the system, append the org CA to your downloaded cacert.pem and use it with --cacert from step 3.

### 5. Rule out clock skew

```bash
date -u
```

Expected output: the current UTC time. Certificate validity is checked against the system clock; if it is off by days (common on VMs and containers), fix NTP first, then re-run curl.

## Root cause

curl verifies the server's certificate chain against a local trust store of root CAs. "Unable to get local issuer certificate" means the chain terminated at an intermediate or root that is not in that store. That happens when the store is missing or stale (minimal containers, old images), when a middlebox re-signs the traffic and its CA was never added, or when the server fails to send its intermediate certificates so curl cannot complete the chain.

## Variant phrasings

- `curl (60) SSL certificate problem`
- `unable to get local issuer certificate curl`
- `cURL error 60: SSL certificate problem` (PHP/WordPress)
- `SSL certificate problem: unable to get local issuer certificate` (git, same root cause, fix is git's http.sslCAInfo)

## Edge cases

- Python `requests`, Guzzle, and other libraries bundle their own CA stores (certifi, a vendored cacert.pem). Updating the OS store does not fix them; update the package or set its CA path instead.
- `-k` / `--insecure` is fine for a thirty-second diagnostic to confirm the rest of the request works, but it leaves the connection unverified. Do not ship it as the fix.
- macOS system curl validates against the system keychain rather than a PEM bundle; a persistent 60 there usually means a proxy CA missing from the keychain or a very old OS.
- WAMP/XAMPP on Windows: PHP's cURL reads its own CA file, so the OS store update does not help; point PHP at a current cacert.pem.
