HTTP header checker

ToolPetal's server requests the URL once as ToolPetalBot from a Cloudflare datacenter, reads only the response headers, and stores nothing. Cookie values are redacted before they reach your browser. Grading runs in your browser.

A bare domain such as example.com is checked over HTTPS. Type http:// to test the plain HTTP redirect.

Grade pasted headers instead
One header per line, as printed by curl -sI or copied from the browser's network panel. Nothing is sent anywhere.

By Cobra · Last updated

How the 100 points are split

Seven checks, graded on the final response only. HSTS and CSP carry half the score because they block the attacks that actually happen to ordinary sites: downgrade to HTTP on public Wi-Fi, and injected script. The rest are one-line headers with no reason to be missing.

CheckWhat it stopsFull points forPartial creditPoints
Strict-Transport-SecurityDowngrade to plain HTTP on later visitsmax-age of 31536000 (one year) or more15 for one day up to a year, 5 under a day, 0 for max-age=025
Content-Security-PolicyInjected scripts running on your pagesscript-src (or default-src) with no 'unsafe-inline' unless a nonce or hash is present, and no *, https:, http:, data: or blob: script sources20 with 'unsafe-eval', 12 with 'unsafe-inline' or wide sources, 10 if scripts are not restricted at all, 5 for Report-Only25
frame-ancestors or X-Frame-OptionsClickjacking through a hidden iframeCSP frame-ancestors without wildcards, or X-Frame-Options DENY or SAMEORIGIN5 for wildcard frame-ancestors or the dead ALLOW-FROM15
X-Content-Type-OptionsBrowsers guessing a file is script or HTMLnosniffNone10
Referrer-PolicyPaths and query strings leaking to other sitesno-referrer, same-origin, strict-origin or strict-origin-when-cross-origin7 for origin or origin-when-cross-origin, 5 when missing, 4 for no-referrer-when-downgrade, 0 for unsafe-url10
Permissions-PolicyEmbedded content asking for camera, mic or locationAny non-empty policy2 for the old Feature-Policy name5
Set-Cookie flagsSession cookies sent over HTTP or on cross-site requestsEvery cookie Secure with a SameSite value, or no cookies at all6 if all are Secure but some lack SameSite10

Grades: A is 90 to 100, B is 75 to 89, C is 60 to 74, D is 45 to 59, F is under 45. A final page served over plain HTTP gets an F whatever the points say, because every other header can be stripped in transit.

Worked example: a C that becomes an A

A typical shop on Express behind a CDN returns this:

HTTP/2 200
strict-transport-security: max-age=15552000
content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://www.googletagmanager.com
x-frame-options: SAMEORIGIN
x-content-type-options: nosniff
set-cookie: session=[redacted]; Path=/; Secure; HttpOnly
x-powered-by: Express
CheckEarnedWhy
Strict-Transport-Security15 / 25180 days is under a year
Content-Security-Policy12 / 25'unsafe-inline' with no nonce or hash, so any injected inline script runs
Clickjacking15 / 15X-Frame-Options SAMEORIGIN
X-Content-Type-Options10 / 10nosniff
Referrer-Policy5 / 10Missing, so it rides on the browser default
Permissions-Policy0 / 5Missing
Set-Cookie flags6 / 10Secure, but no SameSite

That is 63 points, a C. The X-Powered-By line costs nothing but shows up as a note. Five changes take it to 100:

Paste both versions into Grade pasted headers to watch the score move. The nonce is the only change that needs code; everything else is config.

Reading the redirect hops

The hop table lists every response in order: its status code, the URL that was requested, and where the Location header pointed. Each redirect hop's own headers sit in a collapsed block under the final header list. For longer chains, loops and www or http mix-ups, the redirect chain checker follows up to 10 hops and says which ones to collapse.

Flagged but not scored

These show up as notes under the grade. They are worth fixing, or worth knowing, but they do not change the letter:

Setting the headers on Nginx, Apache and _headers files

Ship CSP as Content-Security-Policy-Report-Only first if you have inline scripts or third-party tags. A strict policy will break them, and Report-Only tells you where.

Nginx. Use always so the headers are also sent on 4xx and 5xx responses. An add_header inside a location block replaces every add_header inherited from the server block, so repeat them there or keep them all at one level.

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

Apache with mod_headers:

Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set Content-Security-Policy "default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Header unset X-Powered-By

A _headers file (Cloudflare Pages, Netlify) at the root of the build output. On Cloudflare Pages these rules apply to static files, not to responses from Pages Functions, which have to set their own headers.

/*
  Strict-Transport-Security: max-age=31536000; includeSubDomains
  Content-Security-Policy: default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'
  X-Content-Type-Options: nosniff
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: camera=(), microphone=(), geolocation=()

Add cookie flags where the cookie is created, in your framework or session middleware, not in the web server.

Where this check can be wrong

FAQ

Why is my grade different on securityheaders.com or Mozilla Observatory?

Each grader uses its own weights. This one splits 100 points across seven checks, listed in the points table on this page, and grades only the final response. It also fetches from a Cloudflare datacenter as ToolPetalBot, so a site that treats bots differently can send different headers here.

Does the checker send my cookies or log in?

No. ToolPetal's server makes one plain GET request with no cookies and no credentials, so you see what a logged-out visitor gets. Set-Cookie values are replaced with [redacted] before the result reaches your browser. Only cookie names and flags are shown.

Which response gets the grade when a URL redirects?

The last one, the response that did not redirect. Every hop is listed with its status code and Location, and each hop's own headers can be opened separately. Up to 5 redirects are followed.

Do I need X-Frame-Options if my CSP has frame-ancestors?

Not for current browsers. They use frame-ancestors and ignore X-Frame-Options when both are sent. This checker gives full clickjacking points for either one. Keeping X-Frame-Options as well only helps very old browsers.

Why is X-XSS-Protection not scored?

Current browsers no longer have the XSS filter that header controlled, so it does nothing in them. MDN and OWASP recommend sending 0 or leaving it out and relying on Content-Security-Policy. The checker adds a note for any value other than 0 but gives it no points.

Can I check a staging site or an internal URL?

Not by URL. The fetch refuses private, loopback and internal addresses and only uses ports 80 and 443. Copy the response headers instead, for example from curl -sI or your browser's network panel, and use Grade pasted headers. That part runs entirely in your browser.