Back to Checks
HSTS is enabled with recommended max-age and includes subdomains
zone_hsts_enabled
Service: zoneSeverity: high
OfficialBuilt-inVerified
Categories:encryptioninternet-exposed
Resource Type:Zone
Cloudflare zones are assessed for HTTP Strict Transport Security (HSTS) by checking if it is enabled with a max-age of at least 6 months (15768000 seconds) and includes subdomains to instruct browsers to always use HTTPS across the entire domain.
Risk
Without HSTS, browsers may initially connect over HTTP before redirecting to HTTPS.
- Confidentiality: creates a window for SSL stripping attacks where attackers downgrade connections to unencrypted HTTP
- Integrity: first request can be intercepted and modified before HTTPS redirect
- Session hijacking: cookies and credentials may be captured during initial HTTP request
Run this check with Prowler
Run in Prowler CloudRun
prowler cloudflare --checks zone_hsts_enabledRecommendation
Enable HSTS with at least a 6-month max-age (12 months recommended).
- Verify all resources work over HTTPS before enabling
- Enable include_subdomains to protect all subdomains
- Consider HSTS preloading for maximum protection against SSL stripping attacks
- Test thoroughly as HSTS cannot be easily disabled once deployed
Remediation
Terraform
# Enable HSTS with recommended settings
resource "cloudflare_zone_setting" "security_header" {
zone_id = "<ZONE_ID>"
setting_id = "security_header"
value = {
strict_transport_security = {
enabled = true
max_age = 31536000 # Critical: 1 year in seconds
include_subdomains = true # Recommended: apply to all subdomains
preload = true # Recommended: submit to browser preload lists
}
}
}Other
1Log in to the Cloudflare dashboard and select your account and domain
2Go to SSL/TLS > Edge Certificates
3Scroll to HTTP Strict Transport Security (HSTS)
4Click Enable HSTS
5Set Max Age Header to at least 6 months
6Enable Include subdomains and Preload if appropriate
7Acknowledge the warning and click Save
Check Code
from prowler.lib.check.models import Check, CheckReportCloudflare
from prowler.providers.cloudflare.services.zone.zone_client import zone_client
class zone_hsts_enabled(Check):
"""Ensure that HSTS is enabled with secure settings for Cloudflare zones.
HTTP Strict Transport Security (HSTS) forces browsers to only connect via
HTTPS, preventing protocol downgrade attacks and cookie hijacking. This check
verifies that HSTS is enabled with a minimum max-age of 6 months (15768000
seconds) and includes subdomains for complete protection.
"""
def execute(self) -> list[CheckReportCloudflare]:
"""Execute the HSTS enabled check.
Iterates through all Cloudflare zones and validates HSTS configuration
against security best practices. The check verifies three conditions:
1. HSTS is enabled for the zone
2. The includeSubdomains directive is set to protect all subdomains
3. The max-age is at least 6 months (15768000 seconds)
Returns:
A list of CheckReportCloudflare objects with PASS status if all
HSTS requirements are met, or FAIL status if HSTS is disabled,
missing subdomain inclusion, or has insufficient max-age.
"""
findings = []
# Recommended minimum max-age is 6 months (15768000 seconds)
recommended_max_age = 15768000
for zone in zone_client.zones.values():
report = CheckReportCloudflare(
metadata=self.metadata(),
resource=zone,
)
hsts = zone.settings.strict_transport_security
if hsts.enabled:
if not hsts.include_subdomains:
report.status = "FAIL"
report.status_extended = f"HSTS is enabled for zone {zone.name} but does not include subdomains."
elif hsts.max_age < recommended_max_age:
report.status = "FAIL"
report.status_extended = (
f"HSTS is enabled for zone {zone.name} but max-age is "
f"{hsts.max_age} seconds (recommended: 6 months)."
)
else:
report.status = "PASS"
report.status_extended = (
f"HSTS is enabled for zone {zone.name} with max-age of "
f"{hsts.max_age} seconds and includes subdomains."
)
else:
report.status = "FAIL"
report.status_extended = f"HSTS is not enabled for zone {zone.name}."
findings.append(report)
return findings