fix(deploy/site): treat HSTS max-age=0 as a hard failure, not a variance

Enabling HSTS with the Max Age dropdown left at 0 serves
`strict-transport-security: max-age=0`, which the sweep was filing under
"differs from the baseline". That is far too mild: max-age=0 is not weaker
protection, it is an instruction to browsers to DISCARD the HSTS policy
they already hold — so it actively revokes the two-year policy Vercel had
been setting, for every returning visitor.

Now a hard failure regardless of EXPECT_HSTS, with the fix in the message,
since nobody deliberately wants a header whose only effect is to turn
protection off. A non-zero max-age that differs from the baseline stays a
warning: protection is on, the duration is a judgement call.

Caught on the live zone right after enabling HSTS.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LAmkjM7okPdScp9XLW1JVr
This commit is contained in:
Viktor Vaczi 2026-07-27 14:54:13 +02:00
commit 3259fb3c85

View file

@ -247,13 +247,20 @@ assert_parity() {
# once you have enabled it, and it becomes a hard assertion.
_hsts="$(_hdr "$(_headers "$_base/")" strict-transport-security)"
case "$_hsts" in
*max-age=0*)
# Distinct from — and worse than — absent. max-age=0 actively instructs
# browsers to DISCARD any HSTS policy they hold for this host, so it
# revokes the 2-year policy Vercel was setting for every returning
# visitor. Always a hard failure, regardless of EXPECT_HSTS: nobody
# deliberately wants a header whose only effect is to switch protection off.
fail hsts - "max-age=0 — HSTS is OFF and this actively clears the policy browsers already hold. Set Max Age to 12 months or 2 years in SSL/TLS -> Edge Certificates." ;;
*max-age=63072000*) pass hsts - "$_hsts" ;;
"") if [ "${EXPECT_HSTS:-0}" = 1 ]; then
fail hsts - "absent, but EXPECT_HSTS=1"
else
soft hsts - "absent (Vercel sent max-age=63072000) — enable it in SSL/TLS -> Edge Certificates, then set EXPECT_HSTS=1"
fi ;;
*) soft hsts - "$_hsts (differs from the Vercel baseline max-age=63072000)" ;;
*) soft hsts - "$_hsts (differs from the Vercel baseline max-age=63072000, but non-zero so protection is on)" ;;
esac
fi