ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN high
NET::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN
The served certificate chain contains no public key matching a hash that was previously pinned for this host.
What you see
Your connection is not private NET::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN Attackers might be trying to steal your information from example.com
What’s actually happening
One specific site throws a full-page interstitial while every other HTTPS site loads fine. The cert itself looks valid if you click through to inspect it (trusted CA, not expired, hostname matches), which is what makes this confusing. There's usually no 'proceed anyway' link, or clicking it does nothing. Often shows up right after a certificate was renewed or the origin moved to a new host.
Common causes
- A certificate was renewed or reissued with a brand-new key pair, and none of the still-active pins cover the new key (the classic HPKP self-lockout).
- A native mobile app or Electron build ships hardcoded pins (Android Network Security Config, TrustKit, OkHttp CertificatePinner) that weren't updated when the backend cert rotated.
- Corporate MITM/AV proxy (Kaspersky, ESET, BitDefender, Zscaler) re-signs TLS with its own root, so the public key the browser sees never matches the app's expected pin.
- A stale HPKP pin is still cached in an old Chrome profile from before HPKP was removed in Chrome 72 — the browser keeps enforcing a max-age that hasn't expired.
- Pinning to a leaf or intermediate that the CA quietly swapped during reissue (cross-sign change), so the chain no longer contains the pinned SPKI hash.
How to fix it
- Confirm it's pinning, not a normal cert errorOpen chrome://net-internals/#hsts, type the hostname under 'Query HSTS/PKP domain', and submit. If dynamic_pkp lines come back with SPKI hashes, the browser is enforcing a pin. Compare those hashes against the live cert: openssl s_client -connect host:443 -servername host </dev/null | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64. If none match, the pin is the problem.
- Delete the stale pin from the affected profileIn chrome://net-internals/#hsts use 'Delete domain security policies', enter the host, submit. This clears the cached HPKP/PKP entry. Reload. If it comes back, something is re-serving a Public-Key-Pins header — see the next step.
- Stop serving HPKP headers at the originHPKP is dead in every current browser. Grep your server config and CDN for Public-Key-Pins and Public-Key-Pins-Report-Only (nginx add_header, Apache Header set, Cloudflare Transform Rules) and remove them. Reissuing won't help while the header keeps re-pinning the old key.
- Update or rip out pins baked into appsIf this is a mobile/desktop app, the pin is compiled in. Update the pinset to include the new cert's SPKI hash plus a backup pin, ship a release, and force-update clients. For OkHttp that's CertificatePinner.Builder().add(); for Android, the <pin> entries in network_security_config.xml. There is no client-side flush for this — only a new build fixes it.
- Whitelist the MITM root if it's corporateIf the offending key belongs to an AV or corporate proxy, the user can't fix the pin. Add the inspection product's CA to its TLS-scanning exclusion list for that domain, or disable HTTPS scanning for the host.
Stop it recurring
If you pin at all (in apps, since browsers no longer honor HPKP), always ship at least one backup pin for an offline key and validate the live chain against your pinset in CI before every cert rotation.
Related errors