Safeguard
Application Security•

ASVS 5.0 V3.4.1: Send HSTS With a One Year Max Age

ASVS V3.4.1 (Level 1) requires Strict-Transport-Security on every response with max-age of at least one year, plus includeSubDomains at Level 2. Setup and tests inside.

Safeguard Security Team
3 min read

ASVS 5.0 requirement V3.4.1 says every HTTP response must include a Strict-Transport-Security header with a max-age of at least one year, which is 31536000 seconds. For Level 2 and above, the policy must also cover all subdomains with includeSubDomains. The requirement is Level 1, so it applies to every application.

Why it matters

HTTPS protects traffic only if the browser uses it. Without HSTS, a user who types example.com or follows an old http:// link sends the first request in clear text. An attacker on the same network can intercept that request, strip the redirect to HTTPS and sit in the middle. This is the classic SSL stripping attack.

HSTS closes that gap. After the browser sees the header once over HTTPS, it refuses to talk to the site over plain HTTP for the length of max-age and upgrades every request internally, before it leaves the machine. It also turns certificate warnings into hard failures, so users cannot click through a bad certificate.

The one year minimum exists because short values leave a window. A policy that expires after a day only protects people who visited yesterday.

How to implement it

The header value ASVS expects at Level 2:

Strict-Transport-Security: max-age=31536000; includeSubDomains

Send it on all responses, including errors and redirects. Browsers ignore it over plain HTTP, so it is safe to add everywhere, but your HTTP listener should simply redirect to HTTPS.

nginx:

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

The always flag matters: without it nginx omits the header on 4xx and 5xx responses.

Express with Helmet:

app.use(helmet.hsts({ maxAge: 31536000, includeSubDomains: true }));

Apache:

Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

Before adding includeSubDomains, inventory your subdomains. Every one of them, including internal tools, old marketing sites and dev hosts, must work over HTTPS with a valid certificate, or they will break for users who have seen the policy. Roll out in stages: start with max-age=300, then a day, then a week, then the full year.

How to test it

curl -sI https://example.com | grep -i strict-transport-security
curl -sI https://example.com/does-not-exist | grep -i strict-transport-security
curl -sI http://example.com | head -5

The first two must show the header with max-age of at least 31536000 and, at Level 2, includeSubDomains. The second request checks error responses. The third should return a redirect to HTTPS and no HSTS header.

Check every distinct service: the main site, the API host, static asset hosts and any CDN edge. A script that loops over a hostname list and fails on a missing header makes a good CI check.

Common mistakes

Header only on the homepage. Applications often add it in one controller or one proxy location block.

Missing on error pages. Servers drop custom headers on error responses unless told otherwise.

Short max-age left from testing. A max-age=300 that ships to production fails this requirement.

Adding includeSubDomains before checking subdomains. One forgotten HTTP only host becomes unreachable.

Sending it from a service that terminates TLS elsewhere. Set it at the layer that every response passes through.

Quick check

Is HSTS needed if my site redirects HTTP to HTTPS?

Yes. The redirect itself travels over HTTP and can be intercepted. HSTS lets the browser skip that first insecure request.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.