A Security-Headers Grade Counts Headers. It Doesn’t Test Them.
Run a domain through a security-headers scanner and you get a letter grade. The grade is almost always computed the same way: how many of the well-known security headers are present. Six of them do most of the work — Strict-Transport-Security (HSTS), Content-Security-Policy (CSP), X-Frame-Options, X-Content-Type-Options, Referrer-Policy, and Permissions-Policy — and a scanner counts how many you set and maps the count to a letter. All six present, you get an A.
That grade answers a real question, but a narrower one than people read into it. It tells you which headers you remembered to send. It does not tell you whether the ones you sent actually do anything — and for the two that matter most, the difference between "present" and "effective" is an entire security property. A domain can score an A and still be downgradeable, framable, or one XSS away from a stolen session. Here's where a good grade hides a real exposure.
HSTS: max-age=0 is present and off
HSTS is the header that tells a browser "only ever reach me over HTTPS, and don't let the user click through a certificate warning." Its whole behavior lives in the max-age directive — how many seconds the browser should remember to force HTTPS. And a header of exactly Strict-Transport-Security: max-age=0 is valid, present, counts toward your grade, and disables HSTS. max-age=0 is the documented way to turn HSTS off (it tells the browser to forget the policy immediately). A scanner grading present/absent sees the header and gives you the point; the browser sees max-age=0 and enforces nothing.
Even a non-zero HSTS has two quality gates a present/absent grade skips:
includeSubDomains— without it, HSTS protects only the exact host that sent it.www.example.comis covered;example.comand every other subdomain are not.preloadplus amax-ageof at least one year — the bar to get onto the browsers' built-in HSTS preload list, which is what protects the very first visit (before any HSTS header has ever been seen). A header without these still "counts," but the domain isn't preload-eligible and that first-request window stays open.
So "HSTS: present" spans everything from fully preloaded, all subdomains, one-year memory to literally switched off. The grade can't tell them apart. The max-age value can.
CSP: present is the easy 10%
Content-Security-Policy is the header that limits what a page is allowed to load and execute — the main structural defense against cross-site scripting. It's also the header where presence tells you the least, because CSP is a policy language, and most of the policies people ship are permissive enough to defeat the point:
'unsafe-inline'inscript-srcre-permits exactly the inline<script>and event-handler injection that CSP exists to stop. A CSP withunsafe-inlineis present, grades as present, and blocks almost none of the attacks a CSP is for. It's the single most common way a "we have CSP" site has no meaningful CSP.Content-Security-Policy-Report-Onlyis a different header. It reports violations and enforces nothing — it's the staging mode you use to tune a policy before turning it on. Ship only the-Report-Onlyvariant (a common "we'll enforce it later" state) and you have full visibility and zero protection.- A missing or wildcard
frame-ancestorsleaves clickjacking toX-Frame-Optionsalone — andX-Frame-Optionsis the older, weaker control.
None of that shows up in "CSP: present." Reading a CSP for effectiveness means reading the directives — and that's a by-hand job (or a policy-aware linter), not a header-count.
The flags most likely to leak a session aren't graded at all
Here's the exposure a headers grade misses entirely, because it isn't one of the six headers: the security flags on your Set-Cookies. A session cookie missing:
Securecan be sent over plaintext HTTP — exactly what an HSTS gap leaves open.HttpOnlyis readable by JavaScript, which turns any XSS into session theft.SameSite(LaxorStrict) is a primary CSRF control; its absence widens cross-site request forgery.
A domain can present all six graded headers, earn its A, and still set a session cookie with none of these flags — the highest-impact miss on the page, invisible to a grade that only looks at response headers and never at the cookies those responses set.
What a grade is good for — and what to check past it
The present-count grade isn't useless. It's an honest, coarse "did you set these at all," and going from an F to setting all six is real, worthwhile hardening — most of these headers are safe to add and immediately useful. Just don't read the letter as "secure." Once the six are present, the effectiveness questions the grade can't see are:
- HSTS — is
max-agea real value (not0), withincludeSubDomains, and preload-eligible (≥ 1 year +preload)? - CSP — is it enforcing (not only
-Report-Only), and doesscript-srcavoid'unsafe-inline'? - Cookies — do your session
Set-Cookies carrySecure,HttpOnly, andSameSite?
The free security-headers checker grades the six from outside your stack, and then goes past the count where it honestly can: it flags an HSTS header that's effectively off (max-age missing or 0) or not preload-eligible, and it inspects your Set-Cookie flags and reports cookies missing Secure, HttpOnly, or SameSite — the two effectiveness gaps a present/absent grade skips. (Reading a CSP's directives for unsafe-inline is still a by-hand review; the tool reports whether CSP is present, not whether it's strong.) No signup, one domain at a time.
The one-line version: a security-headers grade tells you which headers you set, not whether they work — and the gap is widest exactly where it matters, on HSTS that's switched off, CSP that's been de-fanged with unsafe-inline, and cookie flags no header grade ever looks at. Set all six, then check the three effectiveness questions the letter can't answer.
And headers drift. A CSP relaxed to ship a third-party widget, an HSTS max-age dropped during a cert migration, a Secure flag lost in a cookie-library upgrade — each ships green and quietly re-opens a hole. Merlonix watches HTTP security-header posture the way it watches SSL and DNS: continuously, from outside your infrastructure, and alerts you when a header you relied on weakens — so a policy that silently went from enforcing to report-only is something you hear about from monitoring, not from an incident. Run the free security-headers scan to see where a domain stands right now, and browse the rest of the free tools while you're there.