No 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.
- Severity
- Low
- Who can exploit it
- Someone on the visitor’s network, before the redirect happens
- Found by
- PatchLabs Live posture: your home page’s response headers
- Lab proof
- Not lab-proven: read from your home page’s response
What it is
HSTS (HTTP Strict Transport Security) is one response header: Strict-Transport-Security: max-age=63072000. Once a browser has seen it over HTTPS, it refuses to use plain HTTP for your domain for that many seconds, and won’t let the visitor click past a certificate warning. PL-029 means the header is missing, or its max-age is below 180 days (15,552,000 seconds), too short to cover people who visit now and then.
Without it, a redirect from http:// (PL-027) still leaves one unprotected request every time someone types your domain or follows an old http:// link. That single request is where an attacker on the network can stop the upgrade and keep the visitor on HTTP.
Why AI builders produce it
HSTS lives in hosting config, which app generators rarely write. Some platforms add it to their own subdomains but not to custom domains, so the header disappears exactly when the app gets its real name.
What we see
A synthetic example for app.example.com, shortened. Not taken from any real site.
$ curl -sI https://app.example.com
HTTP/2 200
content-type: text/html; charset=utf-8
# no strict-transport-security line
Check it yourself
curl -sI https://your-app.com | grep -i strict-transport-security
# good: strict-transport-security: max-age=63072000; includeSubDomains
# 180 days = 15552000 seconds; anything lower is reported
The fix
Send this on every HTTPS response. Two years is the usual value. Add includeSubDomains only when every subdomain serves HTTPS, and preload only if you intend to submit the domain to the browsers’ preload list, which is hard to undo.
Strict-Transport-Security: max-age=63072000; includeSubDomains
Vercel
{
"headers": [
{
"source": "/(.*)",
"headers": [
{ "key": "Strict-Transport-Security", "value": "max-age=63072000; includeSubDomains" }
]
}
]
}
Put vercel.json at the root of the project and redeploy. If the file already has a headers array, add the object to it rather than starting a second one.
Netlify
# public/_headers (Vite copies public/ into the publish folder)
/*
Strict-Transport-Security: max-age=63072000; includeSubDomains
The file must end up in your publish directory (dist for Vite). Bolt projects deployed to Netlify use this file too. The same rule can live in netlify.toml under [[headers]] if you prefer one config file.
Cloudflare
Cloudflare has a switch for this: SSL/TLS → Edge Certificates → HTTP Strict Transport Security (HSTS). Set max-age to 12 months or more, and tick “Include subdomains” only if they all serve HTTPS. On Cloudflare Pages without a proxied zone, use a _headers file as on Netlify.
Lovable
Lovable’s documentation (checked 10 Nov 2026) doesn’t describe a way to set your own response headers on Lovable hosting. It does let you connect a custom domain through Cloudflare: choose “Uses Cloudflare or similar proxy” when you add the domain. Cloudflare can then add the header for you, as in the Cloudflare tab. If that changes, the header and value above are the same wherever you set them.
HSTS has to be a real response header: it can’t be set with a <meta> tag.
Make sure HTTPS works on every hostname first (PL-028): once browsers have cached HSTS, a broken certificate becomes a hard error with no way past it.
Live posture findings come with the header or setting to change. PatchLabs never changes your hosting or your repo.
How PatchLabs finds it
[LOAD] https://app.example.com/ → 200 strict-transport-security not sent FLAG
Live posture reads the Strict-Transport-Security header from the final response of its one https:// page load, after at most 5 redirects, and compares max-age with 180 days. Sites on a top-level domain that is itself on the browsers’ HSTS preload list, such as .app or .dev, pass without the header, since browsers already use HTTPS only for them. It doesn’t look up whether your own domain was submitted to the preload list.
When the pattern is intended
Briefly, while you roll it out: start with a small max-age such as 300, confirm nothing breaks, then raise it. A short value is reported until you do, which is the point.
Why it’s rated low
Low: it matters only on the first or plain-HTTP request, and only to someone positioned on the network. It is a cheap, one-line fix, so it still counts: 5 points in the Live posture grade.
Related findings
Site doesn’t force HTTPS
The plain http:// address of your site serves the page instead of redirecting to https://.
PL-028TLS 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.
PL-030No Content-Security-Policy
Your page sends no Content-Security-Policy, so any script that gets onto it can run and send data anywhere.
Guides
Free check
Does your site have PL-029?
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.