medium7 min readLast updated May 27, 2026

HSTS Preloading: Eliminate HTTP Completely and Prevent Downgrade Attacks

HSTS preloading tells browsers to always use HTTPS, even on the first visit. Learn how to configure HSTS, submit to the preload list, and avoid common pitfalls.

What is HSTS?

HTTP Strict Transport Security (HSTS) is an HTTP response header that tells browsers: "Only connect to this site over HTTPS. Never use HTTP. Even if the user types http:// or clicks an HTTP link, upgrade it to HTTPS automatically."

The header looks like this:

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

Without HSTS, a user who types yourcompany.com into their browser first makes an HTTP request, then gets redirected to HTTPS. That initial HTTP request is unencrypted and vulnerable to interception.

The problem HSTS solves: SSL stripping

SSL stripping is a man-in-the-middle attack where an attacker intercepts the initial HTTP request and proxies the connection, presenting HTTP to the user while connecting to the real server over HTTPS. The user sees no padlock and no warning -- they just browse over plain HTTP while the attacker reads everything.

HSTS prevents this by ensuring the browser never makes that initial HTTP request. Once the browser has seen the HSTS header from your site, all future requests go directly to HTTPS -- no redirect, no interception window.

The first-visit problem

HSTS has a critical weakness: it only works after the browser has visited your site at least once and received the header. The very first visit is still vulnerable because the browser does not yet know your site requires HTTPS.

This is where HSTS preloading comes in.

What is HSTS preloading?

HSTS preloading is a mechanism where your domain is hardcoded into browsers as HTTPS-only. Major browsers (Chrome, Firefox, Safari, Edge) ship with a preload list -- a compiled list of domains that must always use HTTPS. If your domain is on this list, the browser uses HTTPS on the very first visit, before it has ever connected to your server.

The preload list is maintained at hstspreload.org and shared across all major browsers.

Requirements for HSTS preloading

To be eligible for the preload list, your domain must meet all of these requirements:

  1. Serve a valid TLS certificate -- no chain issues, no expired certificates
  2. Redirect from HTTP to HTTPS on the same host -- http://yourcompany.com must redirect to https://yourcompany.com
  3. Serve the HSTS header on the HTTPS response with:
    • max-age of at least 31536000 (1 year)
    • includeSubDomains directive
    • preload directive
  4. All subdomains must support HTTPS -- the includeSubDomains directive means every subdomain under your domain will be forced to HTTPS

The header must be:

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

Step-by-step: Enabling HSTS and submitting for preloading

Step 1: Ensure all subdomains support HTTPS

This is the most important preparatory step. Once you enable includeSubDomains, any subdomain without a valid TLS certificate becomes inaccessible. Audit every subdomain:

# List subdomains from Certificate Transparency logs
curl -s "https://crt.sh/?q=%25.yourcompany.com&output=json" | \
  jq -r '.[].name_value' | sort -u

# Test each one for HTTPS
for sub in $(cat subdomains.txt); do
  echo -n "$sub: "
  curl -sI "https://$sub" -o /dev/null -w "%{http_code}" --max-time 5 2>/dev/null
  echo
done

If any subdomain does not support HTTPS, fix it before proceeding. This includes internal tools, staging environments, and legacy systems.

Step 2: Start with a short max-age

Do not jump straight to a 2-year max-age. Start short and increase gradually:

# Week 1: 5 minutes
Strict-Transport-Security: max-age=300

# Week 2: 1 day
Strict-Transport-Security: max-age=86400

# Week 3: 1 week
Strict-Transport-Security: max-age=604800

# Week 4: 1 month
Strict-Transport-Security: max-age=2592000

# Final: 2 years with preload
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload

This gradual approach lets you catch any problems before they become long-lived.

Step 3: Configure your web server

Nginx

server {
    listen 443 ssl http2;
    server_name yourcompany.com;

    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

    # ... rest of config
}

# HTTP redirect
server {
    listen 80;
    server_name yourcompany.com;
    return 301 https://$host$request_uri;
}

Apache

<VirtualHost *:443>
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
</VirtualHost>

<VirtualHost *:80>
    ServerName yourcompany.com
    Redirect permanent / https://yourcompany.com/
</VirtualHost>

Caddy

Caddy enables HSTS by default with a 1-year max-age. To add preloading:

yourcompany.com {
    header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
}

Step 4: Verify the header

curl -sI https://yourcompany.com | grep -i strict-transport-security

Also verify on your subdomains. Check that the header is present on error pages too (the always keyword in Nginx handles this).

Step 5: Submit to the preload list

Visit hstspreload.org, enter your domain, and submit. The site will check all requirements before allowing submission.

After submission, it typically takes a few weeks to months for your domain to appear in browser releases. The Chrome preload list is updated with each Chrome release (roughly every 4 weeks), and other browsers follow.

Common HSTS mistakes

Forgetting includeSubDomains

Without includeSubDomains, only the exact domain is protected. An attacker can still perform SSL stripping on subdomains. The preload list requires includeSubDomains precisely because partial protection is insufficient.

Subdomains without HTTPS

If you add includeSubDomains and a subdomain like legacy.yourcompany.com does not have a valid TLS certificate, it becomes completely unreachable. This is the number one cause of HSTS-related outages.

Setting max-age to 0

max-age=0 disables HSTS. It is used to opt out, but if set accidentally, it removes all protection. Some CDNs and load balancers have been known to override the max-age value -- verify the header as received by the browser, not just as configured on the origin.

Not serving HSTS on the HTTPS response

The HSTS header must be served over HTTPS. Browsers ignore HSTS headers received over HTTP (for obvious reasons -- an attacker could forge them). If your redirect sends the header on the HTTP response but not the HTTPS response, HSTS is not active.

CDN and proxy interference

If you use a CDN or reverse proxy, the HSTS header must be present in the response that reaches the browser. Some CDNs strip or override headers. Test from outside your infrastructure:

# Test what the actual browser sees
curl -sI https://yourcompany.com | grep -i strict

Removing a domain from the preload list

HSTS preloading is semi-permanent. Removing a domain from the preload list requires:

  1. Removing the preload directive from your HSTS header
  2. Submitting a removal request at hstspreload.org
  3. Waiting for the removal to propagate through browser releases (months)

During this waiting period, your domain is still forced to HTTPS in all browsers that have not updated yet. This is why the gradual rollout in Step 2 is so important -- make sure HTTPS works everywhere before committing to preloading.

HSTS and your security headers audit

HSTS is one of several critical HTTP security headers. A complete security headers configuration includes HSTS alongside Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, and Permissions-Policy.

You can test all of them at once with Security Headers or Mozilla Observatory.

How SurfaceScan helps

SurfaceScan checks every domain and subdomain for HSTS configuration on each scan. It detects missing HSTS headers, insufficient max-age values, missing includeSubDomains, and subdomains that would break if includeSubDomains were enabled. The TLS section flags domains that qualify for preloading but have not been submitted, and tracks HSTS deployment progress across your entire attack surface.

Related articles