HSTS header is present with reasonable max-age
Why it matters
HTTPS enforcement prevents plaintext connections, but HSTS goes further: it instructs the browser to refuse HTTP for your domain entirely for up to a year after the first visit, eliminating SSL-stripping attacks that can silently downgrade an HTTPS connection before the browser even sees it. Without a max-age of at least 31536000, an attacker who intercepts the first request can strip the redirect and operate in plaintext for every subsequent session. RFC 6797 defines the spec; OWASP A02 identifies the absence of HSTS as a cryptographic failure that enables credential theft.
Severity rationale
High because a missing or short-lived HSTS header leaves the window open for SSL-stripping attacks that HTTPS redirects alone cannot prevent.
Remediation
Configure the Strict-Transport-Security header with a full-year max-age in your framework config or middleware. A short max-age is nearly as dangerous as no HSTS — browsers forget the policy quickly.
// next.config.js
headers: [{
key: 'Strict-Transport-Security',
value: 'max-age=31536000; includeSubDomains'
}]
Verify the header is live with curl -I https://yoursite.com | grep Strict-Transport after deployment. Do not configure this only in development environments — production config is what matters.
Detection
-
ID:
hsts-enabled -
Severity:
high -
What to look for: Count every location where Strict-Transport-Security could be configured: framework config (
next.config.*headers), middleware, deployment config (vercel.json,netlify.toml), and security middleware (helmet). Verify themax-ageis at least 31536000 (1 year). -
Pass criteria: HSTS header is configured with
max-ageof at least 31536000 seconds (1 year).includeSubDomainsis recommended but not required for pass. -
Fail criteria: No HSTS configuration found, or
max-ageis less than 31536000. -
Skip (N/A) when: Never — every HTTPS site should have HSTS.
-
Do NOT pass when: HSTS is only configured in development/local config (e.g.,
next.config.dev.jsor behindif (process.env.NODE_ENV === 'development')) but not in production config. Also do NOT pass whenmax-ageis 0, which effectively disables HSTS. -
Report even on pass: Report the configured
max-agevalue and whetherincludeSubDomainsis present: "HSTS configured with max-age=31536000, includeSubDomains present." -
Note: This check fails even if
https-enforcedpasses via platform default — HSTS must be explicitly configured with the correct max-age.https-enforcedverifies transport-level HTTPS; this check verifies browser-side enforcement via the HSTS header. -
Cross-reference: For HTTPS enforcement in deployment config, the Performance & Load audit covers server configuration and TLS setup.
-
Detail on fail:
"No Strict-Transport-Security header configured in next.config.js, middleware, or deployment config"or"HSTS max-age is 3600 (1 hour) — should be at least 31536000 (1 year)" -
Remediation: HSTS tells browsers to always use HTTPS for your site, even if the user types
http://. Without it, the first visit to your site could be intercepted. Add the header:// next.config.js headers: [{ key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubDomains' }]After deploying, verify with:
curl -I https://yoursite.comand confirm the header appears.
External references
- cwe · CWE-319 — Cleartext Transmission of Sensitive Information
- cwe · CWE-523 — Unprotected Transport of Credentials
- owasp:2021 · A02 — Cryptographic Failures
- external · RFC-6797 — HTTP Strict Transport Security (HSTS)
Taxons
History
- 2026-04-17·v1.0.0·Initial import from security-headers·automated