mediumSeverity: mediumRisk ratingHow usable this gap is to an attacker. Severity sets the posture penalty: critical −40, high −20, medium −10, low −4, info −1. Higher severity means fix it sooner.Netlify headers (netlify.toml / _headers)Where it livesImplementationThis fix is applied in: Netlify headers (netlify.toml / _headers). That's the surface you'll edit, DNS, response headers, or a static file.~5 minTime to fixEffortRoughly 5 minutes of hands-on work, propagation aside. Most of these are copy-paste.+10 posture+10 postureScore impactPoints this fix recovers in the ApeCyber posture score (0–100). Posture = 100 minus the severity penalty of every open finding; clearing this finding adds these points back.

HSTS: force https on the first visit, not the second

Strict-Transport-Security closes the window where a first visit gets silently downgraded to http

The threat

You redirect http to https, so you assume you are covered. You are not, on the first visit. When someone types your domain, or clicks an old http:// link, their browser’s very first request goes out over plain http, before your redirect ever runs. On shared or public wifi that first request is the whole game: someone on the same network answers it, keeps the visitor on http, and reads or rewrites everything from there. This is SSL stripping, and it runs from a point-and-click tool.

Strict-Transport-Security closes the window. It tells the browser one thing: for this domain, never use http again, for the next two years. After a visitor has seen the header once, their browser silently upgrades every future request to https on its own, before anything touches the network. preload closes even the first-ever visit by shipping your domain inside the browser itself.

The exact fix

One header. On Netlify, add it to netlify.toml:

# netlify.toml
[[headers]]
  for = "/*"
  [headers.values]
    Strict-Transport-Security = "max-age=63072000; includeSubDomains; preload"

Or the _headers form:

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

What each part does:

  • max-age=63072000: two years, in seconds. This is the value browsers expect for preload. Do not ship a short “test” value and forget it, a long max-age is the entire point.
  • includeSubDomains: covers www, app, mail, every subdomain. Required for preload.
  • preload: your opt-in to the browser’s built-in HSTSHSTSHTTP headerHTTP Strict Transport Security: a header that forces browsers to always use HTTPS for your domain, defeating downgrade and SSL-strip attacks. list, which is what protects the genuine first visit.

Before you add preload, three things must be true, or you can lock users out of a subdomain you forgot about:

  1. A valid TLS certificate on the root domain and every subdomain.
  2. http redirects to https (you almost certainly have this already).
  3. The header is served on the root domain over https.

Once it has been live for a day, submit the domain once at hstspreload.org. That is the only step that reaches past your own config, and it is a one-time submission.

Want a cautious rollout? Ship max-age=300; includeSubDomains first (five minutes of coverage), confirm nothing on any subdomain breaks, then raise it to 63072000 and add preload. Skip this only if you already know every subdomain is https-clean.

Verify it

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

You want Strict-Transport-Security: max-age=63072000; includeSubDomains; preload to come back on an https response. That is the whole check.

Proof

apecyber.com serves this exact header on every response and is submitted for preload, so a browser that has never seen the site still refuses to load it over http. Five minutes of config, a clean −10 off the posture score, and the first-visit downgrade simply stops existing.