Security headers tell the browser how to treat your pages: only over HTTPS, never inside another site’s frame, without guessing file types and with only the features you use. Enter a URL to see which headers are sent, a score out of 100 and the exact line to add for each missing header.
Table of Contents
Headers that matter in 2026
Strict-Transport-Security (HSTS) keeps browsers on HTTPS; use a max-age of at least 180 days. Content-Security-Policy limits where scripts, frames and forms may load from, and its frame-ancestors directive replaces X-Frame-Options for clickjacking protection. X-Content-Type-Options: nosniff stops MIME sniffing.
Referrer-Policy controls how much of the URL is sent to other sites, and Permissions-Policy switches off camera, microphone, geolocation and similar features you do not use. Cross-Origin-Opener-Policy isolates your window from pop-ups; same-origin-allow-popups is safe even with payment pop-ups.
Adding headers on Apache, LiteSpeed and nginx
On Apache and LiteSpeed Enterprise, add lines such as Header always set X-Content-Type-Options “nosniff” to .htaccess or the virtual host. OpenLiteSpeed ignores Header lines in .htaccess, so set them under the context Header Operations in WebAdmin or send them from the application. On nginx use add_header with the always flag.
Introduce a Content-Security-Policy in Content-Security-Policy-Report-Only mode first, read the violation reports for a week or two, then enforce it. A policy that breaks analytics or payment scripts does more harm than good.
Headers you can drop
X-XSS-Protection controlled a filter that modern browsers removed; send X-XSS-Protection: 0 or nothing. Expect-CT and Public-Key-Pins (HPKP) are obsolete. Version numbers in Server or X-Powered-By help attackers match known bugs, so hide them with expose_php = Off and the server signature settings.
Security Headers Checker at a glance



How to use this tool
- Enter a page address. Without a scheme,
https://is assumed. Ports 80, 443, 8080 and 8443 can be tested. - Test the page that matters: headers can differ between the home page,
/wp-login.php, a checkout page or an API path, so check those separately. - Press Check headers. The checker follows up to 8 redirects and grades the response of the final URL; the redirect chain is shown when there was one.
- Work through the fixes under the score, then expand All response headers to see exactly what the server sent.
Results are cached for 5 minutes. If you use a page cache or CDN, purge it after changing headers, or the checker may still receive the old cached response.
How to read the results
The score is the weighted share of checks passed: a pass earns the full weight, a warning half. Grades: A+ from 97, A from 90, B from 80, C from 65, D from 50, F below. Checks that do not apply (no cookies on the page, or the optional Cross-Origin-Opener-Policy not set) are shown for information and left out of the total.
| Check | Weight | Pass | Warning or fail |
|---|---|---|---|
| Strict-Transport-Security | 15 | max-age of 15552000 seconds (180 days) or more | Warning for a shorter max-age; fail when missing, max-age=0, or the page is not on HTTPS |
| Content-Security-Policy | 15 | Enforced, with default-src or script-src and no 'unsafe-inline' for scripts | Warning for 'unsafe-inline', for a policy without a script rule, or for report-only; fail when missing |
| Clickjacking protection | 10 | CSP frame-ancestors, or X-Frame-Options DENY or SAMEORIGIN | Fail when neither is present or X-Frame-Options has any other value |
| X-Content-Type-Options | 10 | Exactly nosniff | Fail otherwise |
| Referrer-Policy | 8 | no-referrer, same-origin, strict-origin, strict-origin-when-cross-origin, origin or origin-when-cross-origin | Warning when missing or set to unsafe-url or no-referrer-when-downgrade. With a list of values, the last one counts. |
| Permissions-Policy | 8 | Present | Warning when missing |
| Version disclosure | 7 | No version numbers in Server and no X-Powered-By, X-AspNet-Version, X-AspNetMvc-Version or X-Generator | Warning listing what leaked |
| Cookie flags | 5 | Every cookie has Secure (on HTTPS), HttpOnly and SameSite | Warning naming each cookie and the missing flags |
| Cross-Origin-Opener-Policy | 4 | Present | Not scored when absent |
Notes under the table flag X-XSS-Protection values other than 0, and the obsolete Expect-CT and Public-Key-Pins headers. They do not change the score.
A baseline set you can copy
These lines are safe on almost any site: they enforce HTTPS, block MIME sniffing and framing by other sites, trim referrer data, switch off unused device features, and add a starter CSP that cannot break scripts. On a typical site they score an A; an enforced script-src policy without 'unsafe-inline' is what lifts the CSP check, and the grade, to the top. Add includeSubDomains to HSTS only when every subdomain works over HTTPS.
Apache and LiteSpeed Enterprise (.htaccess or the virtual host):
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Header always set Content-Security-Policy "upgrade-insecure-requests; base-uri 'self'; object-src 'none'; frame-ancestors 'self'"
</IfModule>
nginx (inside the server block):
add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "upgrade-insecure-requests; base-uri 'self'; object-src 'none'; frame-ancestors 'self'" always;
IIS (web.config):
<system.webServer>
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
<add name="X-Content-Type-Options" value="nosniff" />
<add name="X-Frame-Options" value="SAMEORIGIN" />
<add name="Referrer-Policy" value="strict-origin-when-cross-origin" />
</customHeaders>
</httpProtocol>
</system.webServer>
Cloudflare: switch on HSTS under SSL/TLS » Edge Certificates, and add the other headers with a response header transform rule. If you use the Add security headers managed transform, note that it also sends X-XSS-Protection: 1; mode=block and Expect-CT, which this checker reports as outdated.
Common problems and how to fix them
You added a header but the checker says it is missing
Check what the server really sends, bypassing the browser cache:
curl -sI https://example.com/ | grep -iE "strict-transport|content-security|x-frame|x-content-type|referrer|permissions"
If it is missing there too, the usual causes are: on nginx, a location block with its own add_header, which stops all add_header lines from the server block being inherited; on Apache, Header set without always, which skips redirects and error pages; on OpenLiteSpeed, Header lines in .htaccess, which it ignores; or a page cache serving a copy stored before the change.
“X-Frame-Options “SAMEORIGIN, SAMEORIGIN” is not a valid value”
The header is sent twice, usually once by the web server and once by the application or a security plugin. The two values are joined into one, which browsers may treat as invalid. Remove one of them. The same happens with doubled HSTS or nosniff headers. ALLOW-FROM is also rejected: it is obsolete and ignored by current browsers, so use CSP frame-ancestors to allow specific sites.
The Content-Security-Policy broke the site
The browser console shows what was blocked, with a message such as Refused to load the script 'https://cdn.example.net/app.js' because it violates the following Content Security Policy directive. Move the policy to Content-Security-Policy-Report-Only, add the sources the site really needs, and enforce it again once the console is clean on every page type.
HSTS shows a warning or is ignored
A short max-age (for example 300 seconds while testing) earns a warning; raise it to at least 15552000, or 31536000 for one year. Browsers ignore HSTS sent over plain HTTP, so the header must come on the HTTPS response, and HTTP should redirect to HTTPS first. Check the redirects with the HTTP redirect checker.
Version disclosure: “Server: Apache/2.4.x” or “X-Powered-By: PHP/8.x”
Set expose_php = Off in php.ini (in cPanel, MultiPHP INI Editor) to drop X-Powered-By. For Apache, set ServerTokens Prod and ServerSignature Off (in WHM: Apache Configuration » Global Configuration); for nginx, server_tokens off; in the http block.
Cookie flags warning
For PHP sessions set these in php.ini, then test again with a fresh session:
session.cookie_secure = 1
session.cookie_httponly = 1
session.cookie_samesite = "Lax"
Cookies that JavaScript must read, such as some consent and analytics cookies, cannot be HttpOnly. A warning that names only those is acceptable.
Official documentation: MDN HTTP headers, OWASP Secure Headers Project, RFC 6797 (HSTS).
Related guides: Harden Shared cPanel Server: Secure CageFS and ModSecurity Setup · DirectAdmin ModSecurity: Secure OWASP CRS Setup · LiteSpeed Cache WordPress cPanel: Best Settings.
Frequently asked questions
Why is Cross-Origin-Embedder-Policy not scored?
COEP blocks every third-party resource that does not opt in, which breaks most analytics, video embeds and payment widgets. It is useful for special cases only, so it is not part of the grade.
Is a report-only Content-Security-Policy enough?
It is the right first step because it shows what a policy would block without breaking anything. It does not protect visitors, so it scores as a warning until the policy is enforced.
Why does another scanner give a different grade?
Each scanner weights headers differently and some test only the first response. This checker follows redirects, scores the final page and lists every header it saw so you can compare.
Should I submit my site to the HSTS preload list?
Only when every subdomain works over HTTPS for good. Preloading requires max-age of at least one year with includeSubDomains and preload, and removal from browser lists takes a long time.
What happens to visitors with HSTS if my certificate expires?
Browsers refuse the connection and do not offer a way to click through the warning. Automate renewal and monitor expiry before setting a long max-age.
Do I still need X-Frame-Options if I set frame-ancestors?
Current browsers follow CSP frame-ancestors and ignore X-Frame-Options when both are set. Sending both does no harm and covers older browsers; the checker passes either one.
Do security headers have to be on every page?
Yes, set them at server level so every response gets them. The checker grades one URL, so test pages served by different code, such as the login page or a checkout, separately.
Why does the checker flag X-XSS-Protection: 1; mode=block?
The XSS filter it controlled has been removed from browsers and could be abused in some cases. Current advice is X-XSS-Protection: 0 or no header, so the checker adds a note; it does not lower the score.
Which Referrer-Policy should I choose?
strict-origin-when-cross-origin keeps full URLs within your own site and sends only the domain to others, which suits most sites. Use no-referrer or same-origin if outside sites should not learn where visitors came from.