1. Abstract
Require HTTPS for repeat browser visits with a valid Strict-Transport-Security policy.
HSTS tells browsers to keep using HTTPS after the first secure visit, reducing downgrade, SSL-stripping, and mixed-transport risk for repeat users.
2. Classification
- Check ID
- hsts
- Check version
- 1.0.0
- Package path
- lib/checks/hsts/versions/1.0.0
- Category
- Security & Trust
- Subcategory
- Security & Trust
- Check group
- Browser Trust
- Check group ID
- browser-trust
- Maturity
- Established
- Scope
- site
- Check weight
- 1
3. Input And Output Contracts
- Input
- [email protected]
- Output
- [email protected]
- Resources inspected
- Strict-Transport-Security, max-age, includeSubDomains, preload
4. Scoring Semantics
| Step ID | Title | Weight | Description |
|---|---|---|---|
applicability | Validate HSTS applicability | 0.1 | Confirm the final URL is an HTTPS DNS hostname where HSTS can protect browser traffic. |
header-presence | Find Strict-Transport-Security | 0.2 | Check the relevant HTTPS response for a Strict-Transport-Security header. |
syntax | Parse HSTS directives | 0.2 | Parse RFC 6797-style directives, duplicate directive names, malformed values, and unknown extension directives. |
max-age | Validate max-age | 0.2 | Validate required max-age, explicit removal, deployment minimum, and one-year strength. |
subdomains | Review subdomain scope | 0.1 | Record includeSubDomains and the operational scope of subdomain enforcement. |
preload | Review preload opt-in | 0.1 | When preload is present, validate header-level preload requirements without requiring preload for ordinary HSTS. |
http-transport | Review HTTP transport | 0.1 | Fail plain HTTP final URLs and record that STS sent over HTTP is not effective. |
5. Package Documentation
HSTS Header Check v1.0.0
Status
- Version:
1.0.0 - Check identifier:
hsts - Input contract:
[email protected] - Output contract:
[email protected] - Scope: site
Abstract
This check validates the Strict-Transport-Security response header on the scanned page. It checks whether the final URL is eligible for HSTS, whether the header is present on HTTPS, whether the directives are parseable, whether max-age is strong enough for this assessment, and whether optional includeSubDomains and preload signals are used safely.
Plain HTTP final URLs fail this check because browsers ignore HSTS received over insecure HTTP.
Motivation
HSTS reduces downgrade and SSL-stripping risk for repeat browser visits. After a browser observes a valid HSTS policy over HTTPS, future HTTP requests to that host are upgraded to HTTPS before loading, and certificate errors become non-bypassable for that known HSTS host.
HSTS is effective only when the policy is delivered over a secure HTTPS connection. Sending Strict-Transport-Security on HTTP does not protect users.
Normative Model
RFC 6797 defines HTTP Strict Transport Security.
The Strict-Transport-Security header uses semicolon-separated directives. The required directive is max-age, a non-negative integer number of seconds. Directive names are case-insensitive and directive order is not significant.
Important RFC behavior:
- browsers process HSTS only when received over secure transport
max-age=0removes the HSTS policyincludeSubDomainsextends the policy to subdomains- directives must not appear more than once in one header field
- servers should emit only one
Strict-Transport-Securityheader field; when a
runtime folds multiple observed fields into one comma-separated value, this check evaluates the first field value and warns about the duplicate emission
- unknown directives are ignored when the rest of the header is valid
- servers must not emit STS over insecure HTTP
- IP literals are not noted as HSTS hosts
The preload directive is not part of RFC 6797. It is an ecosystem opt-in used by hstspreload.org.
Applicability
The check applies to the scanned final URL and expects a public HTTPS DNS hostname.
The check fails when the final URL is HTTP, non-HTTPS, localhost, private/internal, or an IP literal, because the scanned page is not delivering an effective public-site HSTS policy.
Pass Criteria
The check passes baseline HSTS validation when:
- the final URL is HTTPS
- the host is a DNS hostname
Strict-Transport-Securityis present- the header is syntactically parseable
max-ageappears exactly oncemax-ageis a non-negative integermax-ageis at least15552000seconds- no duplicate directives are present
- no malformed directives or malformed directive values are present
includeSubDomainsis present for the strongest baseline posture
If preload is present, the header-level preload requirements must also be satisfied: max-age of at least 31536000, includeSubDomains, and preload.
Warning Criteria
Warnings include:
- multiple
Strict-Transport-Securityheader fields appear to have been
observed; the first value is evaluated and duplicate emission is reported
- HSTS is syntactically valid but
max-ageis below15552000seconds and above zero - HSTS is valid and strong enough, but
includeSubDomainsis absent max-ageis quoted but otherwise parseable- unknown extension directives are present
preloadis present but header-level preload requirements are incompletepreloadis present and appears header-eligible, because domain-wide preload readiness still requires operational verification outside this single-response check
Failure Criteria
Failures include:
- final URL is HTTP
- final URL is not HTTPS
- final URL is localhost, private/internal, or an IP literal
- HTTPS public DNS hostname omits
Strict-Transport-Security - header lacks
max-age max-ageappears more than oncemax-ageis not an integermax-age=0- directives are malformed enough that browsers must ignore the STS header
- a directive appears more than once in one header field
Strict-Transport-Securityis emitted on HTTP
Duplicate header fields are not treated the same as duplicate directives inside the first effective field value. The check evaluates the first observed STS field value for policy strength and reports the additional folded values as a warning so operators can remove duplicate emission at the application, proxy, or hosting layer.
Evidence Model
The check emits step-level evidence for:
- final URL, scheme, hostname, and host classification
- header presence
- summarized header value
- first effective header value when duplicate fields were folded together
- duplicate folded header values, when observed
- parsed directive names
- duplicate directives
- unknown directives
- malformed directive summaries
- parsed
max-ageseconds - whether
max-agemeets15552000and31536000thresholds includeSubDomainspresencepreloadpresence and header-level preload eligibility- whether the final URL was HTTP
Evidence must not include cookies, authorization headers, full response header dumps, request credentials, or unrelated sensitive values.
Validation/Scoring Steps
applicability(0.10): validate final URL scheme and host eligibility. HTTP final URLs fail.header-presence(0.20): check forStrict-Transport-Security.syntax(0.20): parse directives, duplicate names, malformed values, and unknown extension directives.max-age(0.20): validate requiredmax-age,max-age=0, deployment minimum, and one-year strength.subdomains(0.10): evaluateincludeSubDomains.preload(0.10): ifpreloadis present, validate header-level preload requirements and warn about unverifiable operational requirements.http-transport(0.10): fail plain HTTP final URLs and record that STS over HTTP is ineffective.
Standard Behavior
If the final URL is HTTP, the result is fail.
If the final URL is HTTPS for a public DNS hostname and the HSTS header is missing or malformed, the result is fail.
If the header is RFC-valid but weaker than this check's deployment threshold, the result is warning.
If the header is RFC-valid, meets the deployment threshold, and includes includeSubDomains, the result passes baseline HSTS validation.
If preload is present, the check validates only header-level preload requirements. It does not claim the domain is actually preloaded.
Non-Standard And Real-World Behavior
Security scanners often grade HSTS more strictly than RFC 6797 by expecting long max-age values and includeSubDomains. This check separates protocol validity from production posture:
- RFC-valid HSTS can use any non-negative
max-age max-age=0is valid syntax but removes protection and fails this check- this check requires at least
15552000seconds for a pass 31536000seconds is the header threshold for preload eligibilitypreloadis optional and should be used only after domain-wide readiness review
Hstspreload.org currently recommends HSTS but does not recommend preloading by default because removal can be slow and subdomain impact is broad.
Non-Goals And Limitations
This check does not:
- prove TLS certificate validity beyond what the scan runtime already observed
- prove the domain is on a browser preload list
- crawl every subdomain to prove
includeSubDomainssafety - verify every hstspreload.org operational requirement
- validate every application route
- replace TLS configuration scanning such as protocol versions, cipher suites, OCSP, or certificate-chain auditing
- require
preloadfor ordinary HSTS - treat an STS header observed over HTTP as effective browser protection
References
Source: lib/checks/hsts/versions/1.0.0/docs.md
6. Version Changelog
hsts v1.0.0 Changelog
- Validates
Strict-Transport-Securitydirective syntax, requiredmax-age, deployment-strength threshold, subdomain scope, and preload opt-in requirements. - Fails plain HTTP final URLs because browsers ignore HSTS outside secure transport.
- Distinguishes ordinary HSTS from preload eligibility.
- Evaluates the first folded duplicate
Strict-Transport-Securityheader field and reports duplicate header emission as a warning instead of mis-parsing later folded values as directives.
Source: lib/checks/hsts/versions/1.0.0/changelog.md