Cert Rejected: Certificate Transparency Log Mismatch

Chrome rejects an otherwise valid cert with NET::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED. The cert was issued but never logged to CT, or its SCTs are bad.

Your cert chain looks clean. openssl verify passes, the chain is complete, the hostname matches, the expiry is well in the future. Yet Chrome 50+ refuses the connection with NET::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED. Firefox and Safari may load the site fine. This is Certificate Transparency (CT): since 2018 Chrome requires that every publicly-trusted TLS cert prove inclusion in at least two CT logs via Signed Certificate Timestamps (SCTs). When the SCTs are missing, malformed, from disqualified logs, or your CA forgot to embed them, Chrome rejects the cert outright with no user clickthrough. Private CAs and corporate CAs are exempt only if their roots are not in Chrome’s default trust store; if you use a “real” CA, CT is mandatory.

Common causes

Ordered from most common in practice.

1. Internal CA cert without SCTs hits a Chrome-trusted root by accident

You issued a cert from your internal CA. The internal CA’s intermediate happens to chain up to a publicly-trusted root (because you cross-signed for convenience, or imported a Chrome-trusted root into the chain). Chrome treats it as a public cert and demands CT — but your internal CA doesn’t log to CT, so no SCTs.

How to spot it: openssl s_client -connect yourdomain.com:443 -servername yourdomain.com shows a chain that ends at a public root. The leaf has no SCT extension.

2. CA accidentally issued without embedding SCTs

A legitimate public CA had a bug or a manual workflow step missed CT logging. The cert is real but lacks SCTs. Rare with major CAs (Let’s Encrypt, DigiCert) but happens occasionally with smaller CAs or new products.

How to spot it: openssl x509 -in cert.pem -noout -text | grep -A 10 "CT Precertificate" shows nothing. Crt.sh search for your cert serial returns empty.

3. SCTs delivered via TLS extension but server doesn’t support it

CAs can deliver SCTs three ways: embedded in cert (X.509 extension), via TLS extension during handshake, or via OCSP stapling. If your CA chose TLS-extension delivery and your web server (older nginx, certain haproxy versions) doesn’t forward the extension, Chrome sees no SCTs.

How to spot it: Cert itself has no embedded SCT. openssl s_client -ct -connect yourdomain.com:443 shows no SCTs in handshake. Server version is old enough to predate the feature.

4. SCTs were valid at issuance but the log got distrusted

Chrome periodically retires CT logs (e.g. a log operator goes out of business, or a log is found compromised). Certs whose only SCTs are from now-retired logs become CT-non-compliant retroactively.

How to spot it: Cert has SCTs but tls.sh or crt.sh shows the issuing log is no longer in Chrome’s trusted list. New cert issuance from the same CA produces SCTs from current logs.

5. Cert is brand new and the SCT timing window hasn’t lined up

CT requires at least two SCTs from logs operated by different organizations, AND specific time-of-issuance distribution rules. A cert issued in the last few minutes may temporarily fail CT validation in some clients while logs propagate.

How to spot it: Cert issued within the last hour. Error clears in a few minutes. Re-issue fixes immediately.

6. MitM proxy injecting cert breaks CT

Corporate TLS inspection proxies (Zscaler, Bluecoat, etc.) re-sign every cert with the corporate CA. The injected cert has no SCTs because the corporate CA doesn’t log to CT. Within Chrome’s enterprise policy this is allowed; outside it, it fails.

How to spot it: Issue is only seen on corporate / school networks. The cert in browser DevTools is issued by something like “Corporate Root CA”, not your real CA.

Before you start

  • Confirm the user really is hitting CT error, not a generic cert error — the exact code NET::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED is the only diagnostic for this.
  • Identify the CA that issued your cert and check its CT logging policy.
  • Have the cert’s PEM file accessible — you’ll inspect it offline.
  • Know whether the affected user is on a corporate/managed network with TLS inspection.

Information to collect

  • The exact Chrome error code from the user.
  • Output of openssl s_client -connect yourdomain.com:443 -servername yourdomain.com -showcerts.
  • Output of openssl x509 -in cert.pem -noout -text | grep -A 30 "CT".
  • Cert serial number — used to search crt.sh.
  • The issuing CA and intermediate names.
  • Chrome version on the affected client.

Step-by-step fix

Order: confirm CT is really the issue, then fix at issuance.

Step 1: Confirm the diagnosis with openssl and crt.sh

Pull the cert:

openssl s_client -connect yourdomain.com:443 -servername yourdomain.com </dev/null 2>/dev/null | openssl x509 -outform PEM > cert.pem

Check for embedded SCTs:

openssl x509 -in cert.pem -noout -text | grep -A 20 "Precertificate"
openssl x509 -in cert.pem -noout -text | grep -A 5 "Signed Certificate Timestamp"

You want to see a list of SCTs with log IDs and timestamps. Empty output = no embedded SCTs.

Cross-check on crt.sh:

https://crt.sh/?q=yourdomain.com

If your cert appears in crt.sh, it was logged. If not, the CA never published it.

Step 2: If cert lacks SCTs entirely, re-issue from a CA that logs reliably

The fastest fix is a fresh cert from Let’s Encrypt, ZeroSSL, or any major public CA — all of them embed SCTs at issuance now.

sudo certbot certonly --webroot -w /var/www/letsencrypt -d yourdomain.com

Inspect the new cert for embedded SCTs:

openssl x509 -in /etc/letsencrypt/live/yourdomain.com/cert.pem -noout -text | grep -A 5 "Signed Certificate Timestamp"

You should see at least two entries. Deploy and the error clears.

Step 3: If using internal CA, decide between two paths

Path A: Make the internal CA not chain to a public root. Then Chrome treats it as private, no CT required. Achieve this by:

  • Using a self-signed root specific to your org.
  • Distributing that root to client trust stores via MDM / group policy.
  • Removing any cross-sign to a public root.

Path B: Use a real public cert (Let’s Encrypt with DNS-01 works even for internal-only domains, since the validation is DNS not HTTP).

Pick Path B unless your domain is on a private TLD (.internal, .corp) that isn’t in the public DNS.

Step 4: If server isn’t forwarding TLS-extension SCTs, upgrade or switch delivery mode

If your CA delivers SCTs via TLS extension (e.g. some private deployments of DigiCert / Sectigo), confirm your web server supports forwarding:

  • nginx 1.13+ has ssl_ct on; ssl_ct_static_scts /path/to/scts/; in some builds.
  • haproxy 2.0+ supports SCT delivery via TLS extension natively.
  • Most modern Apache supports it via mod_ssl_ct (third-party).

Easier path: ask the CA to switch delivery mode to “embedded” (SCT baked into cert extension) so the web server doesn’t need to do anything special.

Step 5: For corporate TLS-inspection issues, fix policy or accept the limitation

If users on a corporate network can’t reach your site due to TLS inspection breaking CT:

  • Recommend the corporate IT add your domain to a TLS-inspection bypass list.
  • Or accept that managed-Chrome installs typically have policy RequireCT = OFF for corporate CA-signed inline certs.
  • This is not really your problem to fix on your origin — communicate the constraint, don’t try to weaken your cert.

Step 6: Add cert.sh / CT monitoring to catch future issues early

Use https://crt.sh/?q=yourdomain.com or set up an automated CT log watcher:

# pseudo-monitor: alert if a cert for our domain shows up in CT that we didn't issue
curl -s "https://crt.sh/?q=yourdomain.com&output=json" | jq '.[] | select(.entry_timestamp > "2026-05-01")'

This detects rogue cert issuance AND confirms your own certs are being logged.

Verify

  • openssl x509 -in cert.pem -noout -text | grep "Signed Certificate Timestamp" returns at least two SCTs.
  • Chrome loads https://yourdomain.com without error on the affected client.
  • https://crt.sh/?q=yourdomain.com shows the new cert serial within minutes of issuance.
  • Chrome DevTools → Security tab shows cert as valid with no CT warnings.
  • A test from a clean Chrome incognito window on a non-corporate network confirms success.

Long-term prevention

  • Always use a CA known to embed SCTs: Let’s Encrypt, ZeroSSL, DigiCert, Sectigo, GlobalSign — all current.
  • Never cross-sign your internal CA to a public root unless you intend to issue from the public root.
  • Set up CT monitoring with cert-spotter, crt.sh watchers, or commercial offerings (Hardenize, Censys) to detect missing or unexpected certs.
  • After any major Chrome release, sanity-check that none of your certs are on now-disqualified logs.
  • Document your cert-issuance flow including SCT delivery mode so an unknown engineer can troubleshoot in a year.

Common pitfalls

  • Assuming “the cert chains, therefore it’s valid” — Chrome’s CT check is independent of chain validity.
  • Re-issuing the same cert via the same CA when the CA’s logging is broken; you get the same SCT-less cert.
  • Trying to disable CT in Chrome user-side — only works via enterprise policy on managed installs, not for general users.
  • Forgetting that Chrome’s CT enforcement applies to ECDSA certs and RSA certs equally; algorithm doesn’t matter.
  • Not verifying SCTs after a CA migration — the new CA might use TLS-extension delivery that your server silently drops.

FAQ

Q: Why does Firefox load the site fine but Chrome blocks it?

Firefox does not currently enforce CT for general public sites (as of writing). Chrome and Safari (with their own CT log lists) do enforce. The cert is “valid” by RFC standards but fails Chrome’s stricter policy.

Q: Can I tell Chrome to skip CT for my domain?

Only via enterprise managed-Chrome policies (CertificateTransparencyEnforcementDisabledForUrls), which doesn’t apply to general users. There is no per-user opt-out.

Q: My CA says they DO log to CT but my cert has no SCTs. What’s going on?

Likely the CA logs the cert but delivers SCTs via TLS extension or OCSP stapling instead of embedding. Check your web server supports the delivery method, or ask the CA to switch to embedded mode for new issuances.

Q: Does CT apply to wildcard certs?

Yes, identically. Wildcard certs are issued the same way and must have SCTs from qualifying logs.

Related: SSL cert delay, SSL mixed content warning, CAA record blocks cert issuance, SSL cert auto-renewal failed silently.

Tags: #Troubleshooting #SSL #certificate-transparency #chrome #Debug