HTTP security headers checker
Paste a site's response headers and see which of the standard browser protections it sends, which it is missing, and exactly what to change. The result updates as you type.
Paste-in tool. Your browser cannot fetch another site's headers for a web page (CORS
forbids it), and WebPeeks has no server to do it, so nothing you paste leaves your browser.
Run this in a terminal (on Windows 10 or 11, type curl.exe), then paste everything it prints.
The -L follows redirects so you see the final page's headers.
curl -sIL https://example.com/ 64 / 100
HTTP/2 200 · 7 warnings · 2 passed
- WarnHSTS max-age is 183 days
Reasonable, but below the one year (31536000) the preload list requires.
- WarnContent-Security-Policy is set (3 directives)
The CSP evaluator finds 1 serious problem and 2 warnings in it. Paste the policy there for the details.
- WarnReferrer-Policy is not set
Current Chrome, Firefox and Safari default to strict-origin-when-cross-origin, which is sensible. Setting it explicitly makes the behaviour the same in every browser.
- WarnPermissions-Policy is missing
Optional, but a short policy such as camera=(), microphone=(), geolocation=() stops embedded third-party content from asking for those permissions.
- WarnServer header reveals a version: nginx/1.24.0
A version number tells an attacker which known vulnerabilities to try. Most servers can be told to omit it (nginx: server_tokens off).
- Warnx-powered-by: PHP/8.2.12
Advertises the software stack for no benefit to visitors. Remove it.
- WarnCookie session lacks Secure, SameSite
Secure keeps it off plain HTTP; HttpOnly hides it from JavaScript (omit only if scripts must read it); SameSite limits cross-site sending (Chromium defaults to Lax when absent).
- PassX-Frame-Options: SAMEORIGIN
Other sites cannot put this page in a frame, which prevents clickjacking.
- PassX-Content-Type-Options: nosniff
Browsers will not guess a different content type than the one declared, which stops some upload-based attacks.
Score breakdown
| Check | Points |
|---|---|
| Strict-Transport-Security | 20 / 25 |
| Content-Security-Policy | 9 / 25 |
| Clickjacking protection | 15 / 15 |
| X-Content-Type-Options | 15 / 15 |
| Referrer-Policy | 5 / 10 |
| Permissions-Policy | 0 / 10 |
All headers in the response
| Header | Value |
|---|---|
| date | Sun, 27 Sep 2026 12:00:00 GMT |
| content-type | text/html; charset=utf-8 |
| server | nginx/1.24.0 |
| strict-transport-security | max-age=15768000 |
| content-security-policy | default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.example.net; img-src 'self' data: |
| x-content-type-options | nosniff |
| x-frame-options | SAMEORIGIN |
| x-powered-by | PHP/8.2.12 |
| set-cookie | session=3f9a1c; Path=/; HttpOnly |
| cache-control | no-cache |
How to get the headers to paste
The quickest way is curl -sI https://your-site/, which sends a HEAD request and prints only
the headers. Add -L to follow redirects: a site that sends http:// to
https://, or example.com to www.example.com, answers the first
request with a redirect whose headers are often different from the page's. When you paste a whole
redirect chain, the checker splits it into responses and grades the last one.
A few servers answer HEAD differently from GET. If the result looks wrong, use
curl -s -D - -o /dev/null https://your-site/ (on Windows, -o NUL), which makes
a normal GET request and prints the headers. In a browser, open the developer tools, go to the Network
tab, reload, click the first request and copy the response headers; Chrome and Firefox both have a
"Raw" toggle that gives exactly the Name: value lines this tool expects.
How the grade is worked out
Six headers are scored, out of 100. The weights are this site's own judgement of how much each header protects an ordinary website, not an industry standard: other graders weigh things differently and will not always agree with this one. What matters more than the letter is the list of findings, which says what each header does and what to send instead.
| Check | Points | Full marks for |
|---|---|---|
| Strict-Transport-Security | 25 | max-age of at least one year (20 for 180 days or more, 10 for less) |
| Content-Security-Policy | 25 | An enforced policy with no serious findings; 10 off per serious problem, 3 per warning, never below 5 |
| Clickjacking protection | 15 | X-Frame-Options DENY or SAMEORIGIN, or CSP frame-ancestors |
| X-Content-Type-Options | 15 | nosniff |
| Referrer-Policy | 10 | no-referrer, same-origin, strict-origin or strict-origin-when-cross-origin (5 if absent) |
| Permissions-Policy | 10 | Any Permissions-Policy (5 for the old Feature-Policy) |
The letter follows from the total: A at 90 or more, B from 75, C from 60, D from 40, and F below that.
Other things the checker notices, such as a Server header that gives away a version
number, an X-Powered-By header, or a cookie without Secure, are listed as
warnings but do not change the score, because their weight depends too much on the site.
A worked example
The example pre-loaded above is a typical small PHP site behind nginx. It scores 64, a C:
- HSTS is present with
max-age=15768000, about 183 days. That is over the 180-day mark but under a year, so it gets 20 of 25. - The CSP exists but allows
'unsafe-inline'scripts, which is the one thing a CSP is mostly there to stop. It also has noobject-srcand nobase-uri. One serious problem and two warnings take it from 25 to 9. X-Frame-Options: SAMEORIGINandX-Content-Type-Options: nosniffearn their full 15 each.- There is no Referrer-Policy (5 of 10, since browsers now default to a sensible value) and no Permissions-Policy (0 of 10).
That makes 20 + 9 + 15 + 15 + 5 + 0 = 64. The fastest route to an A is to lengthen HSTS to
max-age=31536000, add Referrer-Policy: strict-origin-when-cross-origin and a
short Permissions-Policy, and replace 'unsafe-inline' with nonces. The first
three are one line each in the server configuration; the fourth usually needs changes to the
application's templates.
What each header is for
Strict-Transport-Security (HSTS)
Tells the browser to use HTTPS for this host, and never plain HTTP, for max-age seconds.
It protects the moment someone types a bare domain name, which would otherwise start with an
unencrypted request that an attacker on the same network could intercept. It is defined in RFC 6797,
and browsers ignore it when it arrives over plain HTTP.
Content-Security-Policy
Lists where scripts, styles, images and other resources may come from. Done well, it means an attacker who manages to inject HTML into a page still cannot run script. The CSP evaluator reads a policy directive by directive.
X-Frame-Options and frame-ancestors
Stop other sites loading your page inside an invisible frame and tricking visitors into clicking on it
(clickjacking). frame-ancestors in the CSP is the modern form; X-Frame-Options still works
everywhere.
X-Content-Type-Options: nosniff
Stops the browser second-guessing the declared Content-Type. Without it, a file uploaded as
an image could in some circumstances be run as a script.
Referrer-Policy and Permissions-Policy
Referrer-Policy controls how much of the current URL is sent to other sites when a visitor follows a link or the page loads a resource. Permissions-Policy switches off browser features (camera, microphone, geolocation, payment and so on) that the page does not use, so embedded third-party content cannot ask for them either.
Where this check stops being reliable
- It sees exactly one response. Headers often differ between the homepage, other pages, API routes and static files, especially when an application framework sets some and the web server others. Check the pages that matter, not only the root.
- It cannot tell whether the response came over HTTPS. HSTS is only honoured on HTTPS responses, so a
header copied from an
http://request earns points it would not earn in a browser. - A CDN or proxy in front of the site may add or strip headers. Paste what the public URL returns, not what the origin server returns internally.
- It does not test whether the site's TLS setup is sound, whether cookies are scoped correctly, or anything about the application itself. For the certificate, use the certificate decoder.
Common questions
Why can this tool not just fetch my site?
Because it runs entirely in your browser, and browsers do not let a page read another site's response headers unless that site explicitly allows it with CORS. A server could do the fetching, but then every URL you check would pass through that server. Pasting the output of curl keeps the whole check on your own machine.
Is a grade of A the same as a secure website?
No. Headers are one layer. A site with perfect headers can still have an SQL injection bug, a weak admin password or an outdated plugin. What the grade does tell you is whether the browser-side protections that cost almost nothing to switch on have been switched on.
Should security headers go on every response or only HTML pages?
HSTS and X-Content-Type-Options belong on every response. CSP, X-Frame-Options, Referrer-Policy and Permissions-Policy matter on documents (HTML pages and anything that can be framed), and are harmless elsewhere. The simplest reliable setup is to add them all at the web server or CDN level so no route can forget them.
Do I still need X-Frame-Options if my CSP has frame-ancestors?
Not for current browsers, which give frame-ancestors precedence. Sending both is common and does no harm, and covers very old browsers that never implemented frame-ancestors. This tool gives full marks for either one.
What does X-XSS-Protection do now?
Nothing useful. It controlled the XSS auditor in Internet Explorer and old versions of Chrome and Safari; every current browser has removed that feature, and in its last years it could be abused to leak information. The current advice from browser vendors is to send X-XSS-Protection: 0 or not send it at all, and use a Content-Security-Policy instead.