Security headers "fail validation" when an automated scanner such as securityheaders.com or Mozilla Observatory reports that a recommended HTTP response header is missing, malformed, or set to a value too permissive to help. A failing grade is not evidence that your site has been breached — it is evidence that a layer of defense-in-depth is absent, so any attack that does land (cross-site scripting, clickjacking, or an HTTPS downgrade) meets no browser-enforced resistance. The grade you get (an A–F letter from securityheaders.com, or a 0–100 score from Observatory) reflects only which headers you send, not whether your server is compromised. A clean, healthy site routinely scores F for the simple reason that nobody added the headers, and a compromised site can still score A.
That is the summary an AI Overview will give you. Here is what it can't show you: which headers actually move the needle, the exact failure each one leaves open, and the order to fix them without breaking your own pages. The rest of this guide is the concrete version — a grading map, a symptom-to-fix table, and the deploy sequence that keeps Content-Security-Policy from taking your site down the moment you enforce it.
How grading actually works
A header scanner makes one request to your URL and inspects the response headers. It never logs in, never fuzzes inputs, and never looks at your application code. That is the single most important thing to understand about the grade: it measures configuration, not security. The letter is a proxy for "how many recommended headers are present and sane," nothing more.
Because the check is purely about presence and syntax, "failing validation" breaks into three distinct failure modes, and each has a different fix:
- Missing — the header is simply not sent. Most common, and the easiest to fix.
- Malformed — the header is present but the value is wrong (a typo in a CSP directive,
max-agewritten as a string, a mode keyword misspelled). The browser may silently ignore the whole header. - Permissive — the header is present and valid but set so loosely it provides no protection (
Content-Security-Policy: default-src *, or an HSTSmax-ageof a few seconds).
A scanner that returns a low grade rarely tells you which of the three you have. That distinction is exactly what the next table resolves.
The headers that matter, what failure exposes, and how to fix it
| Header | What a failure exposes | Correct baseline value | Priority |
|---|---|---|---|
| Strict-Transport-Security (HSTS) | SSL-stripping / downgrade to plain HTTP on first or subsequent visits | max-age=31536000; includeSubDomains; preload | Fix first |
| Content-Security-Policy (CSP) | Cross-site scripting; injected scripts run with full page privileges | Start Content-Security-Policy-Report-Only, then enforce a per-source allowlist | Fix first |
| X-Content-Type-Options | MIME-sniffing — browser executes an uploaded file as script | nosniff | Quick win |
| frame-ancestors (CSP) + X-Frame-Options | Clickjacking — your page framed inside an attacker's site | frame-ancestors 'self' plus X-Frame-Options: DENY fallback | Quick win |
| Referrer-Policy | Full URLs (with tokens/IDs) leaked to third parties via the Referer header | strict-origin-when-cross-origin | Polish |
| Permissions-Policy | Unneeded APIs (camera, mic, geolocation) available to injected code | camera=(), microphone=(), geolocation=() | Polish |
The "Priority" column is the part a grade will never give you. Chasing an A by bolting on Referrer-Policy and Permissions-Policy while HSTS and CSP are still missing raises your letter but not your actual security. Fix the two "Fix first" rows before you touch anything else.
Fix the two headers that carry the most risk
HSTS is the cheapest high-impact fix. One header, one value, and downgrade attacks stop being possible for returning visitors:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
The max-age is in seconds — 31536000 is one year, which is the value the HSTS preload list requires. includeSubDomains and preload are prerequisites for submitting your domain to the browser-bundled preload list. Two cautions: only add includeSubDomains once every subdomain serves HTTPS, and treat preload as near-permanent — removing a domain from the preload list takes months to propagate.
CSP is where most self-inflicted outages happen. A policy blocks anything it does not explicitly allow, so the first time you enforce a real policy you will almost certainly block a script or stylesheet you actually depend on. The safe rollout is a two-phase deploy.
A workable starting policy that you tighten from the report data:
Content-Security-Policy-Report-Only:
default-src 'self';
script-src 'self';
style-src 'self';
img-src 'self' data:;
frame-ancestors 'self';
report-uri /csp-report
Watch the report endpoint, add each legitimate source it flags, and only switch the header name from Content-Security-Policy-Report-Only to Content-Security-Policy once the stream goes quiet.
Two grades, two different scanners
If you validate on more than one tool you will get more than one grade, and they are not measuring the same thing.
| Scanner | Scale | What it weighs | Best used for |
|---|---|---|---|
| securityheaders.com | A–F letter | Presence and syntax of response headers only | Fast header-only spot check |
| Mozilla Observatory | 0–100 score | Headers plus cookies, CORS, redirects, subresource integrity | Broader configuration audit |
Passing one is not passing the other. securityheaders.com can hand you an A while Observatory docks you for insecure cookie flags it also inspects. Run both, and remember that neither is a vulnerability scanner — a high score on both still says nothing about SQL injection, auth flaws, or business-logic bugs.
Where header configuration silently regresses
Most "we had an A last quarter and now we're at C" cases are not attacks. They are configuration drift:
- A CDN or WAF was added or reconfigured and now strips or overrides headers your origin sets.
- A framework upgrade changed default headers (many frameworks ship their own CSP defaults that clobber yours).
- A reverse-proxy rule was edited and dropped a header block during an unrelated change.
- A new subdomain went live without the header configuration the apex domain had.
This is why the last FAQ answer says to re-scan after every infrastructure change, not just once. Header hygiene is a maintenance task, not a one-time project.
Validate your own headers
Run your live URL through our Security Headers Analyzer to see exactly which of the three failure modes — missing, malformed, or permissive — applies to each header, then work the "Fix first" rows above before chasing a letter grade. Pair it with a full read of what HTTP security headers are and the common misconfigurations to avoid the mistakes that turn a hardening pass into an outage.
Conclusion
A failing security-header grade is a to-do list, not an alarm. It tells you a defensive layer is absent — not that anyone has walked through the open door yet. Fix HSTS and CSP first because they block the attacks that actually happen, deploy CSP in report-only mode so you don't take your own site down, and re-scan after every infrastructure change because header configuration drifts. The letter grade is a means to that end, never the goal itself.