TLS certificate is invalid, expired or expires within 21 days
Browsers will block your site, or soon will, because its HTTPS certificate doesn’t check out.
- Severity
- High or medium
- Who can exploit it
- Every visitor sees a browser warning; anyone on their network gains
- Found by
- PatchLabs Live posture: the TLS handshake of the home page load
- Lab proof
- Not lab-proven: read from the TLS handshake
What it is
Your HTTPS certificate proves to the browser that it is talking to your domain. PL-028 is reported in two strengths. High: the certificate is invalid (it doesn’t cover the hostname, isn’t signed by a trusted authority, or the chain is incomplete) or has already expired. Medium: it is valid today but expires within 21 days.
An invalid or expired certificate puts a full-page warning in front of every visitor. Most leave; the ones who click through have been taught to ignore the one warning that tells them someone is intercepting the connection. That is why an invalid or expired certificate always sets the Live posture grade to F, whatever else passes.
Why AI builders produce it
Managed hosts issue and renew certificates on their own, so certificates rarely expire on a default domain. They expire after a change nobody connected to TLS: DNS moved to a new provider, a CAA record added that doesn’t allow the host’s certificate authority, a domain pointed at two hosts at once, or a certificate uploaded by hand for a launch and forgotten.
What we see
A synthetic example for app.example.com, shortened. Not taken from any real site.
$ curl -sI https://app.example.com
curl: (60) SSL certificate problem: certificate has expired
$ openssl s_client -connect app.example.com:443 -servername app.example.com </dev/null 2>/dev/null \
| openssl x509 -noout -enddate
notAfter=Oct 30 11:02:41 2026 GMT
Check it yourself
# who issued it, which names it covers, and when it expires
openssl s_client -connect your-app.com:443 -servername your-app.com </dev/null 2>/dev/null \
| openssl x509 -noout -issuer -enddate -ext subjectAltName
# curl refuses an invalid certificate and says why
curl -sS -o /dev/null https://your-app.com && echo "certificate OK"
# a CAA record can stop renewals: it must allow your host's authority
dig +short CAA your-app.com
Check every hostname you use, including www: each needs its own name on the certificate.
The fix
A managed certificate should renew about a month before it expires without anyone touching it. If yours didn’t, something stopped the host from proving you own the domain. Find that, and the renewal follows.
Vercel
Vercel issues Let’s Encrypt certificates for domains in your project and renews them automatically, as long as the domain’s DNS points at Vercel. Open Settings → Domains: a domain with a configuration warning can’t renew. If you have a CAA record, it must allow letsencrypt.org.
your-app.com. CAA 0 issue "letsencrypt.org"
Netlify
Netlify also uses Let’s Encrypt and renews automatically while DNS points at Netlify. Under Domain management → HTTPS, use Renew certificate after fixing DNS. If you uploaded your own certificate, Netlify can’t renew it for you: replace it before the date, or switch back to the managed one.
Cloudflare
When the site is proxied, visitors see Cloudflare’s edge certificate, which renews on its own (SSL/TLS → Edge Certificates). Behind it, with Full (strict), your host still needs a valid certificate of its own: if that one expires, visitors get a Cloudflare error page instead of your site. A Cloudflare Origin CA certificate on the host is a long-lived option for that hop.
Lovable
Lovable generates and installs the certificate for a connected custom domain and its documentation says you don’t need to upload or reissue one. If the check fails, the usual cause is DNS: records changed or removed after connecting, or a proxy in front. If the domain goes through Cloudflare, the edge certificate is Cloudflare’s; check it there.
Live posture findings come with the header or setting to change. PatchLabs never changes your hosting or your repo.
How PatchLabs finds it
[TLS] app.example.com:443 issuer Let's Encrypt expires 2026-11-24 · 14 days FLAG medium: renew before it lapses
Live posture reads the certificate from the TLS handshake of the one https:// page load it makes: the issuer, the names it covers, the protocol version and the expiry date, which the report shows as days left. It doesn’t try other ciphers or protocol versions. Daily re-checks on a verified domain mean a renewal that silently fails shows up 21 days before visitors notice.
When the pattern is intended
Never on a public site. A staging host with a self-signed certificate is common, but keep it off the domains people use, and don’t verify it for Live posture.
Why it’s rated high or medium
High when the certificate is invalid or expired: the site is effectively down for most visitors, and the grade is always F. Medium when it expires within 21 days: nothing is broken yet, but a failed renewal is already likely.
Related findings
Site doesn’t force HTTPS
The plain http:// address of your site serves the page instead of redirecting to https://.
PL-029No HSTS header, or max-age under 180 days
Browsers aren’t told to use HTTPS only, so a visitor’s first request can still go out over plain HTTP.
PL-034Page loads scripts or styles over plain HTTP
Your HTTPS page pulls a script or stylesheet from an http:// address, which anyone on the network can replace.
Guides
Free check
Does your site have PL-028?
Type your site’s address. The free headers check loads your public home page once, like any visitor, and grades HTTPS, the certificate, security headers, cookie flags and mixed content. No sign-up, and the result isn’t stored.
Last reviewed 10 Nov 2026. Finding IDs are stable: link to them freely. Spotted a mistake? Tell us.