Evaluating HTTP security header policy strength: present isn't the same as strong
A security headers check reporting a header as 'present' only confirms it was sent — judging whether it's actually doing its job means reading the specific value against a known-weak or known-strong pattern for that header, since a Content-Security-Policy, HSTS max-age, or Referrer-Policy can each be technically present while providing close to none of the protection they're meant for.
By AdminKit team, Netbase JSC · Updated October 31, 2026
Presence is step one; strength is a separate question
AdminKit’s HTTP security headers check, like any headers check, reports two things for each recommended header: whether it’s present, and the exact value sent. How to read an HTTP security headers result covers what each header does; this guide is about the second part — reading that value against a known-weak or known-strong pattern, since a present header with a permissive value can protect a site barely more than no header at all. The OWASP Secure Headers Project maintains exactly this kind of reference: not just which headers to send, but which values within them actually do the intended work.
Content-Security-Policy: the directive value is the whole question
A Content-Security-Policy header being present tells you nothing about its strength on its own — only its directives do. Two patterns OWASP flags as effectively hollow:
default-src *or an unscopedscript-src *— allows scripts (and other resources) from any origin at all, which defeats CSP’s core purpose of restricting where executable content can come from.unsafe-inlineorunsafe-evalinscript-src— permits inline<script>blocks oreval()-style dynamic code execution, which is precisely the mechanism most injected-script (XSS) attacks rely on; a policy allowing it provides little protection against the attack class CSP exists to mitigate.
A strong policy instead scopes script-src to an explicit, short allowlist of trusted origins, or better, uses a per-response cryptographic nonce or hash so the browser only executes script tags the server explicitly marked, regardless of anything injected elsewhere in the page.
Strict-Transport-Security: max-age and includeSubDomains are the two levers
RFC 6797 accepts any positive max-age as a technically valid header, which means “present” covers both a robust year-long policy and a token one lasting a few hours that offers almost no durable protection. hstspreload.org’s submission requirements give a concrete, documented bar for what counts as strong: a max-age of at least 31536000 seconds (one year) and the includeSubDomains directive, which is also exactly the threshold our guide to HSTS and HSTS preload walks through in full, including why preload itself isn’t the right next step for every site even once the header is strong.
X-Frame-Options vs frame-ancestors: same job, different strength
Both headers control which origins may embed a page in a frame, the mechanism behind clickjacking. X-Frame-Options only offers DENY or SAMEORIGIN — an all-or-nothing choice. frame-ancestors, a Content-Security-Policy directive, supersedes it in supporting browsers and allows an explicit list of permitted framing origins, giving finer control without losing the all-or-nothing options either. A policy sending only X-Frame-Options is valid and functional, but weaker than one that also sends frame-ancestors, since it can’t express anything more granular than same-origin-or-nobody.
Referrer-Policy: unsafe-url is a regression, not a neutral default
Modern browsers already default to strict-origin-when-cross-origin when no Referrer-Policy header is sent at all. That matters for judging strength: a site that explicitly sets unsafe-url — which sends a page’s full URL, including any sensitive path or query-string contents, to every cross-origin destination it requests from, even a plain-HTTP one — has made its referrer handling weaker than sending no header, not merely failed to improve on a bad default. Any explicit value stricter than that default, such as strict-origin or no-referrer, is doing genuine, verifiable work.
Permissions-Policy: judged by what it restricts, not whether it exists
Unlike CSP, there’s no single well-known “unsafe” Permissions-Policy value to flag — the strength question is which browser features (camera, microphone, geolocation, and others) a policy explicitly restricts, and to which origins. A page that doesn’t use these features but also sends no Permissions-Policy leaves every feature at the browser’s own default allowance within that page’s context, including for any third-party content it embeds; explicitly denying features a page doesn’t need shrinks what any embedded script or iframe could ever request, regardless of what it later tries.
Reading the whole result as a strength audit, not a presence checklist
A site can report every recommended header as present and still be in meaningfully worse shape than one missing a header or two, if the “present” values are the permissive patterns above. Read each value against the OWASP Secure Headers Project’s reference table rather than counting checkmarks, and prioritize Content-Security-Policy and Strict-Transport-Security first — scoping a wide-open CSP or lengthening a short max-age typically closes a bigger real gap than adding a header that was missing outright.
Next step: check your own headers’ actual values
Run AdminKit’s HTTP security headers check against your own URL, then read each present header’s value against the patterns above rather than stopping at the present/missing column. If the site’s transport encryption is also worth confirming alongside its headers, checking TLS certificate chain completeness covers the companion check these headers assume is already in place.
This guide is general information, not a security audit of your specific network — see our disclaimer for what AdminKit's guidance does and does not commit to.
Frequently asked questions
What makes a Content-Security-Policy weak even though it's present?
A CSP that's permissive in practice does almost nothing against the attacks it's meant to stop, regardless of being technically present. The OWASP Secure Headers Project flags specific weak patterns: a policy whose script-src (or the default-src it falls back to) is set to * or includes unsafe-inline or unsafe-eval allows essentially any script to run, including an attacker's injected one, which is exactly what CSP exists to prevent. A strong CSP instead scopes script-src to specific trusted origins, or uses a per-response nonce or hash so only explicitly marked script tags execute at all.
What HSTS max-age actually counts as strong?
RFC 6797 doesn't itself mandate a minimum max-age — any positive value is a technically valid header — but a short one, like a few hours or days, barely protects a returning visitor and offers nothing for anyone who doesn't visit again within that window. hstspreload.org, which documents the stricter bar sites aim for if they want browsers to enforce HTTPS even earlier, requires at least 31536000 seconds (one year) plus the includeSubDomains directive before a domain can even be considered for preloading — that threshold is a reasonable line between a token HSTS header and one doing real, durable work.
Is X-Frame-Options: SAMEORIGIN as strong as using frame-ancestors?
It covers the same basic clickjacking protection, but frame-ancestors (a Content-Security-Policy directive) is the stronger, more current control: it supports an explicit list of allowed framing origins, not just a same-origin-or-nothing choice, and browsers that support frame-ancestors ignore X-Frame-Options when both are present. A policy relying on X-Frame-Options alone, with no frame-ancestors directive at all, is the weaker of the two valid configurations, not an invalid one — it's a gap compared to best practice, not a failure.
Why is Referrer-Policy: unsafe-url considered a weak value, if any value at all counts as 'present'?
Because unsafe-url is a deliberate opt-out of the protection the header exists to provide: it sends a page's full URL, including anything sensitive in its path or query string, to every cross-origin request a page makes — even a plain-HTTP destination. Modern browsers already default to the considerably stricter strict-origin-when-cross-origin when no Referrer-Policy header is sent at all, so a site that explicitly sets unsafe-url has made its referrer handling weaker than doing nothing, which is a meaningfully different, worse finding than simply having no header.
How do you judge Permissions-Policy strength, since it doesn't have an obvious 'weak value' like CSP's unsafe-inline?
The question is which browser features (camera, microphone, geolocation, and others) the policy restricts, and to which origins. A Permissions-Policy that explicitly denies features the page doesn't use is doing real work by shrinking what any embedded third-party iframe could ever request; a page with no Permissions-Policy at all leaves every feature at the browser's own default allowance for that context, which is typically broader than a page actually needs.
Can a site pass every header as 'present' and still have weak security headers overall?
Yes, and this is the central point of judging strength rather than counting presence: a site can send CSP, HSTS, X-Frame-Options, Referrer-Policy and Permissions-Policy with every one of them set to a permissive, close-to-meaningless value, and a presence-only check would show a clean sheet. Reading each value against the OWASP Secure Headers Project's reference table, rather than treating a checklist of five checkmarks as the goal, is what actually separates real protection from a header sent only to satisfy a scanner.
Want AdminKit to watch this for you?
Free checks tell you the state today. Protective DNS and monitoring tell you when it changes.
Talk to an expert
Huy Nguyen (David), Founder & CEO, Netbase JSC
Ask whether this fix applies to your setup, or get a second pair of eyes on your DNS and mail records.