Blog·jwt security mistakes
Developers: 6 Step HSTS Rollout and Repo Checks to Avoid Lockouts

Developers: 6 Step HSTS Rollout and Repo Checks to Avoid Lockouts

September 8, 2026jwt security mistakessecurity headers checklist

Developers: 6 Step HSTS Rollout and Repo Checks to Avoid Lockouts

HSTS rollout and repository security title card

Enable Strict Transport Security once your site fully serves HTTPS, no exceptions. Start with a short max-age like 300 seconds, confirm every subdomain loads cleanly over HTTPS, then raise the value over several weeks. Hold off on the preload directive until you’ve verified certificates, redirects, and subdomain coverage are all solid, because preload is close to a one-way door once major browsers pick it up.


TL;DR:

  • Deploy HSTS only after confirming all assets and subdomains load securely over HTTPS and avoid enabling preload until certificates and redirects are fully verified.
  • Gradually increase the max-age value from a few minutes to at least one year, and add includeSubDomains only after all subdomains are HTTPS-only, to prevent inadvertent lockouts.
  • Serve the HSTS header over HTTPS responses only, ensuring it is not sent over insecure HTTP or before proper HTTPS implementation to avoid ineffective or risky configurations.
  • Use max-age=0 to reset HSTS policies during rollout mistakes, but be aware that preloaded domains cannot be reset until removal from the preload list fully propagates.
  • Beware that HSTS enforces only transport security; it does not address application-level vulnerabilities, potentially leaving certain security gaps unprotected.

Vibeprod
vibeprod.ai
Check Your Repository Before Launch
VibeProd scans GitHub repositories for exposed secrets and compliance issues, then creates reviewable fixes with plain-English explanations.
Check your repository

Table of Contents

What Is HSTS and How Does HTTPS Enforcement Actually Work?

HSTS is a browser-enforced rule that tells a visitor’s browser to talk to your domain only over HTTPS, never plain HTTP, for a set period. The mechanism is a single response header, Strict-Transport-Security, and once a browser sees it, that domain becomes what the spec calls a Known HSTS Host. The browser stores the policy locally and applies it automatically on every future visit, no server round trip required.

Three things happen once that header lands:

  • The browser rewrites any http:// request to https:// before it even leaves the device.
  • It refuses to let you click through certificate warnings for that domain while the policy is active.
  • With includeSubDomains, every subdomain inherits the same rule, whether you intended that or not.

The catch is the first visit. A browser can’t enforce a rule it hasn’t seen yet, so the very first HTTP request to a domain is unprotected. An attacker on the same network could intercept that one request before the redirect happens. The preload list, covered further down, exists specifically to close that gap.

Strict-Transport-Security Header Syntax and Directives Explained

A safe testing header looks like this:

Strict-Transport-Security: max-age=300

A mature, production-ready header, once you’re confident, looks like this:

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload

Each directive does specific work:

  • max-age sets the policy’s lifetime in seconds. Every fresh response with the header resets that countdown, so a site serving the header consistently keeps the policy alive indefinitely.
  • includeSubDomains extends enforcement to every subdomain under the current one, which is powerful and dangerous in equal measure if any subdomain still runs plain HTTP.
  • preload signals intent to join the hardcoded browser list, but the flag alone does nothing until you actually submit the domain.

One detail trips up a lot of teams: sending the header over an insecure HTTP connection does nothing. Browsers ignore Strict-Transport-Security headers that arrive over HTTP, so the header only counts once the connection is already HTTPS.

Pro Tip: To roll back HSTS on a domain you control, send max-age=0 in an HTTPS response. That clears the stored policy in browsers that have already visited, but it does nothing for a domain sitting on the preload list.

How to Roll Out HSTS Safely (Deployment Checklist)

A staged rollout keeps a bad TLS configuration from locking out real visitors. Follow this order:

  1. Confirm every page, asset, and API endpoint on the domain loads over valid HTTPS, with no mixed-content warnings and no lingering HTTP-only redirects.
  2. Deploy Strict-Transport-Security: max-age=300 first. That’s five minutes, short enough that a mistake resolves itself fast.
  3. Monitor error logs, uptime checks, and any subdomains for HTTPS failures over several days.
  4. Raise max-age incrementally, commonly to a week, then a month, watching for regressions at each step.
  5. Add includeSubDomains only after every subdomain, including staging and internal tools, serves valid HTTPS.
  6. Push max-age to at least one year (31536000 seconds) and add preload only once you’re ready for the permanence that submission requires.

If something breaks mid-rollout, max-age=0 resets you instantly, as long as the domain hasn’t been preloaded. Once it has, that rollback window effectively disappears, since removal from the preload list runs through a separate process that can take weeks to propagate.

Configuring HSTS on IIS, nginx, Apache, and Cloudflare

Each platform sets the header a little differently, and the ordering relative to your HTTP-to-HTTPS redirect matters just as much as the syntax.

  • IIS / Exchange: add the header through IIS Manager’s HTTP Response Headers panel, or script it with PowerShell using New-WebConfigurationProperty against the customHeaders section. Exchange servers sometimes ship separate virtual directories, so confirm the header applies to OWA and ECP paths, not just the default site.
  • nginx: add add_header Strict-Transport-Security "max-age=300" always; inside your HTTPS server block only, never inside the HTTP block that handles the redirect. Sending it before the redirect completes wastes the header entirely.
  • Apache: mod_headers handles this with Header always set Strict-Transport-Security "max-age=300" inside your SSL virtual host. Keep it below any Redirect directives that force HTTPS, so the header ships on the secure response, not the redirect response.
  • Cloudflare and other CDNs: HSTS is typically a toggle in the SSL/TLS dashboard or API, and the edge injects the header for you. Cloudflare’s own guidance warns against pausing the proxy while HSTS is active, since that can silently drop back to HTTP while browsers still expect HTTPS, producing failed connections instead of a clean fallback. DNS-only records bypass the edge entirely, so confirm your origin sends the header directly if you’re not proxying.

A technology adoption checklist built for cross-team rollouts helps here too, since HSTS changes usually touch ops, infrastructure, and whoever owns DNS.

Should You Submit Your Domain to the HSTS Preload List?

Preloading hardcodes your domain into the browser itself, so there’s no first HTTP request to intercept, ever. That closes the bootstrap gap completely, but it trades a security win for an operational commitment you can’t easily undo.

Submission at hstspreload.org requires:

  • max-age of at least one year (31536000 seconds).
  • includeSubDomains present and enforced correctly across every subdomain.
  • A valid certificate, with the header served on the bare root domain, not just www.

Removal exists, but it’s slow. Google Chrome and other browsers pull the list from a shared source, and propagation after a removal request can take weeks or longer to reach users. Treat preload as effectively permanent until that removal finishes. Any subdomain you haven’t finished migrating to HTTPS at submission time becomes unreachable the moment the list updates.

Testing and Fixing Common HSTS Errors

Before trusting any header change, verify it landed. Run curl -I https://yourdomain.com and confirm the Strict-Transport-Security line appears exactly as configured. Browser DevTools’ Network tab shows the same header on the response, and hstspreload.org will flag whether your domain currently qualifies for submission or removal.

When a browser refuses to load your site over HTTP as expected, or throws a certificate error you can’t click through, HSTS is doing its job, sometimes on stale data.

  • Check that your certificate is valid and not expired, since HSTS blocks the override that would normally let a visitor bypass a bad cert.
  • Clear cached HSTS state directly. In Chrome, visit chrome://net-internals/#hsts and delete the domain. In Firefox, clear site data through about:preferences#privacy or the relevant about:config flags.
  • To disable HSTS on a domain you control, serve max-age=0 over HTTPS. Preloaded domains ignore this, since the hardcoded browser list overrides whatever your server sends until removal completes.

Risks and Privacy Trade-offs Worth Knowing Before You Commit

HSTS applies to a domain name across every port, not to a specific IP address, so any non-HTTPS service sharing that domain, like an internal admin tool on a custom port, breaks once includeSubDomains is live. HSTS also only enforces transport security. It says nothing about secure cookie flags, input validation, or leaked credentials, so OWASP is explicit that HSTS supplements rather than replaces application-level security work. One more wrinkle: because the policy persists client-side, it can function as a lightweight fingerprinting signal, worth a line item in any privacy review.

What HSTS Won’t Catch, and Why VibeProd Checks It Anyway

HSTS locks down transport. It won’t flag a hardcoded API key sitting in your repo, a misconfigured CORS rule, or a CI pipeline shipping secrets into a public build. Third-party tools can scan your GitHub repository for such gaps and open reviewable pull requests to address them before you commit to a permanent move like preload. Running that scan alongside your HSTS rollout catches the risks a transport header structurally can’t see.

HSTS and repository scan coverage comparison

When Preload Makes Sense and When to Wait

Preload trades operational flexibility for a closed first-visit gap. Delay it if your DNS or subdomains are still shifting. Commit once your infrastructure is mature and every public-facing service already runs on solid HTTPS.

— Vibeprod

Standards and Tools Worth Bookmarking

For the spec itself, read RFC 6797. For header behavior and browser caching, MDN’s Strict-Transport-Security reference is the clearest explainer. For submission and removal mechanics, use hstspreload.org directly, and pair it with the OWASP HSTS cheat sheet for defense-in-depth context.

Standards and Tools Worth Bookmarking — overview diagram

Before you flip any of this on in production, it’s worth running a check on what else might be exposed. Vibeprod scans your repository for exposed secrets, misconfigurations, and compliance gaps, and opens a fix pull request in plain English, so your HSTS rollout isn’t the only thing standing between your app and a bad launch day.

Sources

FAQ

How Do I Resolve an HSTS Error in My Browser?

Check that your certificate is valid first, since most HSTS errors trace back to an expired or mismatched cert. If the issue persists, clear the browser’s stored HSTS entry for that domain (chrome://net-internals/#hsts in Chrome) and reload.

What Is HSTS on an HTTPS Server?

HSTS is a response header, Strict-Transport-Security, that instructs browsers to only connect to that server over HTTPS for a set duration, blocking downgrade attempts and certificate override clicks.

How Do I Enforce HSTS Correctly?

Serve the Strict-Transport-Security header on every HTTPS response, starting with a short max-age for testing, then increase it over time and add includeSubDomains once every subdomain is confirmed HTTPS-only.

How Do I Disable HSTS on My Website?

Send Strict-Transport-Security: max-age=0 over HTTPS to clear the policy for browsers that already stored it. This does not work for domains on the preload list, which requires a separate removal process that can take weeks to take effect.

Ready to make your app production-ready?

Free scan. No account needed. Results in under 2 minutes.

Scan your repo free →
← Back to all posts