The includeSubDomains trap

One directive can lock every subdomain you own — including the ones you have forgotten about — into HTTPS-only. Here is how to avoid the surprise.

The includeSubDomains directive looks harmless. You add one token to your Strict-Transport-Security header, the certificate scanners give you a green tick, and your security scorecard goes up. What the token actually does is far broader than most people expect: it extends the HTTPS-only rule from the exact host that sent the header to every subdomain beneath it, forever, for anyone whose browser has seen the header once. That reach is the whole point — and also the trap.

What the directive really promises the browser

When a browser receives Strict-Transport-Security: max-age=31536000; includeSubDomains from example.com, it stops treating that as a statement about one host. It records a policy for the entire tree: www.example.com, api.example.com, shop.example.com, and any host you have never even provisioned yet. From that moment, until max-age expires, the browser will refuse to make a plain HTTP request to any of them. It rewrites http:// to https:// internally before a packet leaves the machine.

Crucially, an HSTS failure is not a warning you can click through. If a subdomain cannot complete a valid HTTPS handshake — no certificate, an expired certificate, a self-signed certificate, or simply a service that only ever listened on port 80 — the browser shows a hard error with no bypass button. The user cannot proceed. The subdomain is, for practical purposes, off the internet for anyone who has visited your apex.

The subdomains you forgot you owned

The danger is rarely your public marketing site. It is the long tail of hosts that grew up outside the main deployment pipeline and never got TLS:

None of these send the HSTS header themselves, so a naive audit of the apex misses them entirely. But includeSubDomains on the apex speaks for all of them. The first time an employee or customer loads your main site over HTTPS, their browser quietly arms the policy, and the next time they try to reach that HTTP-only tool it fails with an unbypassable error.

Preload turns the trap into a snare

With dynamic HSTS, at least the policy only applies to people who have already visited you. preload removes even that grace period. The hstspreload.org list bakes your domain — and includeSubDomains is a hard requirement for the list — directly into the browser binary. Now the policy is active on a first-ever visit, for users who have never touched your site, and it ships to hundreds of millions of installs. A forgotten HTTP-only subdomain does not just break for returning visitors; it breaks for everyone, and, as covered in our guide to removing a domain from the preload list, undoing that decision takes months.

Inventory every host before you flip the switch

The fix is boring and effective: know what you own before you make a promise about all of it. Pull the full picture from several angles, because no single source is complete.

For each host, confirm it serves a valid, trusted certificate and answers on 443. A quick way to verify the handshake, chain and expiry for a given name is TLS Studio; to sanity-check the certificate itself — issuer, SANs, validity window — use SSL Studio. A wildcard certificate covers many of these at once, but note that a wildcard only helps a host that is actually configured to present it; a device on port 80 with no HTTPS listener is still broken regardless of what certificate you hold.

Roll out in stages, not in one commit

Treat includeSubDomains as the last step of a sequence, not the first.

  1. Header on the apex only, short lifetime. Start with Strict-Transport-Security: max-age=300 — no includeSubDomains, no preload. This protects the main host while committing you to nothing you cannot walk back in five minutes.
  2. Bring every subdomain onto valid HTTPS. Work through the inventory. Retire dead hosts, add certificates to the live ones, and fix the vendor-hosted stragglers.
  3. Add includeSubDomains, still short. Only once the tree is genuinely HTTPS-clean, add the directive with a modest max-age and watch your error dashboards for a real user cycle.
  4. Ramp the lifetime. Grow max-age towards a year in steps — see what value to actually use — so a mistake never locks visitors in for longer than you can tolerate.
  5. Preload last. Submit to the list only when you are confident the whole tree will stay HTTPS-only indefinitely.

The order matters because HSTS is a promise you make to browsers you cannot recall. includeSubDomains broadens that promise to every host you own and several you have forgotten. Inventory first, fix second, and let the directive be the reward for work already done — not the event that reveals what you missed.


← Back to the HSTS checker