Free security headers checker

Check which security headers a single page sends, what each one does, and which of them are missing, in one scan, no signup.

We read one page, in one state, without signing in. Being clear about the edges is the point: a scanner that implies it sees everything is the one to distrust. See exactly what we can't see →

  • 10 checks each pass, fail, or needs review
  • Under a minute one page, one scan
  • No signup no account, no email

What we check

  • Content-Security-Policy

    Content-Security-Policy: <policy>

    Enforced when the header carries any non-empty policy. We do not grade how strict the policy is, only whether one exists and applies.

    Without a CSP, the browser has no list of origins it is allowed to load or execute code from, so a script that arrives through a comment field, a vulnerable dependency, or a tag manager container someone else can edit is treated as yours and runs with your cookies and your session.

    Learn more about Content-Security-Policy →
  • Content-Security-Policy-Report-Only

    Content-Security-Policy-Report-Only: <policy>

    A report-only policy is real progress, so we say which stage it's in rather than a flat pass or fail. We count its directives, for example a 13-directive policy, and note that renaming the header to Content-Security-Policy is the one step left to enforce it.

    A report-only policy logs violations but blocks nothing, so an attacker's injected script still runs exactly as if no policy existed at all.

    Learn more about Content-Security-Policy-Report-Only →
  • Strict-Transport-Security (HSTS)

    Strict-Transport-Security: max-age=<seconds>

    On sites served over HTTPS, present with a max-age of at least 15,552,000 seconds (180 days), the floor the code names LONG_LIVED_HSTS_MAX_AGE.

    Without it, the first visit over plain HTTP is open to an attacker on the network downgrading or intercepting the connection before it ever reaches HTTPS.

    Learn more about Strict-Transport-Security (HSTS) →
  • HSTS (present but ineffective)

    Strict-Transport-Security: max-age=<seconds> below 15,552,000, or a header with no parseable max-age at all

    A header can be present and still do nothing: max-age=0 actively disables the policy, a value under 15,552,000 seconds expires again before most repeat visitors return, and a header with no valid max-age is ignored by browsers under RFC 6797. We flag all three the same way, not as a pass.

    A max-age below the floor reopens the same downgrade window HSTS exists to close, just on a delay instead of immediately.

    Learn more about HSTS (present but ineffective) →
  • Clickjacking protection

    An X-Frame-Options header with any non-empty value, or the string frame-ancestors anywhere in an enforced Content-Security-Policy

    Either mechanism satisfies it; we do not require both, and we do not read either value. Any non-empty X-Frame-Options passes, whether it says DENY, SAMEORIGIN, or something a browser ignores, and a CSP passes if frame-ancestors appears in it at all. The one X-Frame-Options that does not pass is one sent with nothing after the colon: that fails, and we report clickjacking protection to you as missing rather than as wrong, the same line this scan draws for X-Content-Type-Options. A frame-ancestors directive that only exists in a report-only policy does not count, because it blocks nothing.

    Without it, an attacker can load your page inside an invisible iframe over their own content and trick a visitor into clicking something on your site they never actually saw.

    Learn more about Clickjacking protection →
  • Referrer-Policy

    Referrer-Policy: <value>

    Present with any non-empty value other than unsafe-url. We read the header the way a browser does, taking the last spec-defined token in a comma-separated fallback list, and we fail only when that resolves to unsafe-url. A value with no token we recognise at all, a typo or something newer than this scanner, passes rather than being guessed at, and we do not rank the recognised values against each other.

    Without it, browsers fall back to sending the full referring URL, query string included, to every link a visitor clicks and every third-party resource the page loads.

    Learn more about Referrer-Policy →
  • Referrer-Policy (unsafe value)

    Referrer-Policy: unsafe-url

    The one value we flag by name: it is the least private option the header can hold, and today it satisfies a presence-only check exactly as well as a strict one.

    unsafe-url sends the full URL, query string included, to every destination the page links to or loads a resource from, even over an insecure downgrade: a password reset token or an internal search term in the URL leaks straight to every ad and analytics vendor the page talks to.

    Learn more about Referrer-Policy (unsafe value) →
  • Permissions-Policy

    Permissions-Policy: <directives>

    Present with any non-empty value, and with no requirement on which directives it restricts.

    Without it, any script running on the page, including a compromised third-party tag, can request the camera, microphone, or location with nothing in place to stop it.

    Learn more about Permissions-Policy →
  • Permissions-Policy (legacy Feature-Policy)

    Feature-Policy: <directives>, Permissions-Policy's deprecated predecessor

    We count the directives a Feature-Policy header still lists, for example a 4-directive header, and say how many remain to migrate rather than treating the site as if it never started.

    Feature-Policy is unsupported by every current browser, so the restrictions it lists are silently ignored there: camera, microphone, and location stay unrestricted in whatever browser your visitors actually use.

    Learn more about Permissions-Policy (legacy Feature-Policy) →
  • X-Content-Type-Options

    An X-Content-Type-Options response header with any non-empty value, for instance X-Content-Type-Options: nosniff

    Any non-empty value, not nosniff specifically. We never compare the value, so nosnif with the typo, or banana, or 0, all pass exactly as nosniff does. The one thing that does not pass is no value at all: send the header with an empty or whitespace-only value and the check fails, and we report it to you as missing rather than as wrong. Since nosniff is the only value the specification defines, the gap between what we check and what is correct is rarely practical, but that is the line we actually draw.

    Without it, a browser may MIME-sniff a response and execute a file meant to be read as plain text or an image as a script instead.

    Learn more about X-Content-Type-Options →

What we can't see

  • Headers on pages other than the one you gave us: we read one page, not your whole site.
  • Headers that only appear for logged-in users, or behind a paywall or geofence.
  • Whether a Content-Security-Policy is strict enough to stop a real attacker: we report whether one is enforced, report-only, or absent, not how permissive its directives are.
  • Whether a Referrer-Policy value other than unsafe-url is strict enough for your threat model: strict-origin-when-cross-origin and origin-when-cross-origin both pass the same check today, and we don't rank between them.
  • Headers that vary between requests, a CDN edge, a feature flag, an A/B test: we read the response once, not repeatedly across visits.

Ready to see where you stand?

Scan your site and get your Engineering Score with a prioritized roadmap in under a minute, no signup required.

Scan your site