Skip to content

Security headers check for your website

See which HTTP security headers your site sends and what each one protects. We read the response of your homepage and main hosts, explain every header in plain words and say what to change.

What a security headers check looks at

With every page, your server sends the browser a few instructions: use HTTPS only, load scripts only from these places, do not let other sites embed this page. These are security headers. When one is missing, nothing breaks and it does not mean the site was hacked, but the browser has one guard fewer if something else goes wrong, such as an injected script or a hostile page that frames yours.

The check requests your homepage like a browser, follows redirects and reads the final response. It does the same for the main hosts it finds, such as www or api. It sends ordinary GET requests, plus one request with a foreign Origin header to test CORS. Nothing is submitted to your forms.

Header by header: what we flag

Header Good example What we flag
HTTP to HTTPS http:// redirects to https:// The site opens over http:// with no redirect
Strict-Transport-Security max-age=31536000 on www and the bare domain Missing; max-age under 180 days; HSTS on www only while the bare domain redirects without it
Content-Security-Policy script-src 'self' with nonces or hashes Missing; report-only; 'unsafe-inline' without a nonce or hash; scripts from any source (*, https:, data:); 'unsafe-eval'
X-Frame-Options or frame-ancestors SAMEORIGIN, DENY or frame-ancestors 'self' Neither is set, or frame-ancestors allows any site
X-Content-Type-Options nosniff Missing
Set-Cookie on the homepage Secure, plus HttpOnly and SameSite for session cookies No Secure on HTTPS; SameSite=None without Secure; a session cookie without HttpOnly or SameSite
Server, X-Powered-By, X-AspNet-Version, X-Generator No version numbers An exact version, such as nginx/1.24.0
Access-Control-Allow-Origin Absent, or only your own origins *, worse with credentials, or a foreign origin echoed back

More checks on the same responses

  • /.well-known/security.txt that is missing, expired or invalid, so whoever finds a problem does not know where to report it.
  • Third-party scripts without Subresource Integrity (SRI), and HTTP resources on HTTPS pages (mixed content).
  • Private IP addresses or names like staging or internal in response headers.
  • Responses that set a session cookie without private or no-store in Cache-Control, so a shared cache may keep them.
  • A mixed set: some modern security headers present, but HSTS or CSP missing.
  • Whether the homepage is sent compressed.

How to fix the usual gaps

Most headers take one line in the web server, the hosting panel or the CDN settings. Examples for nginx:

  • add_header Strict-Transport-Security "max-age=31536000" always; on the HTTPS server, for www and the bare domain. Add includeSubDomains and preload only once every subdomain serves HTTPS.
  • add_header X-Content-Type-Options "nosniff" always; and add_header X-Frame-Options "SAMEORIGIN" always;
  • server_tokens off; hides the nginx version; expose_php = Off in php.ini removes the PHP version from X-Powered-By.
  • Mark session cookies Secure, HttpOnly and SameSite in your application or CMS settings.
  • Build CSP last: start with Content-Security-Policy-Report-Only to see what would break, then switch to the enforcing header. Our check treats a report-only policy as not protecting yet.

An nginx pitfall: by default, an add_header inside a location block replaces every add_header line inherited from the server block, so headers can vanish on some pages. Run the check again after each change.

What this check does not do

  • It does not rate Referrer-Policy, Permissions-Policy or the Cross-Origin headers one by one; we only compare them across hosts. OWASP recommends setting Referrer-Policy and Permissions-Policy explicitly, so check them yourself.
  • It gives no letter grade for headers alone.
  • It reads the homepage of each main host, not every page. Inner pages, API responses and admin areas may send different headers.
  • For CSP it checks where scripts may load from. It does not test whether an injection is possible or whether your policy breaks the site.
  • It sees cookies set in the server response of the homepage, not cookies set by JavaScript or after login.
  • It does not ask for X-XSS-Protection: OWASP advises not to set it, or to set it to 0.
  • Hiding version numbers is tidy, but it does not update the software. See the outdated software check.

Questions

Is a missing header a vulnerability?

No. It is a missing layer of protection. Most header findings are marked as hardening, because their impact depends on another weakness that a header check cannot see.

Why do you flag HSTS under 180 days?

That is the threshold our check uses. Longer is better: one year (max-age=31536000) is the minimum for the HSTS preload list, which also needs includeSubDomains.

My CSP needs unsafe-inline for analytics. What can I do?

Move inline scripts to files, or allow them with a nonce or a hash. With 'strict-dynamic' and a nonce, browsers ignore 'unsafe-inline' and host allowlists, and our check accepts that setup.

Why is my result different from another header scanner?

Tools follow redirects differently, read different hosts and use different thresholds. We read the final page after redirects and report the bare domain separately when it redirects without HSTS.

Sources

  1. MDN: Strict-Transport-Security developer.mozilla.org
  2. MDN: Content-Security-Policy script-src developer.mozilla.org
  3. OWASP: HTTP Security Response Headers Cheat Sheet cheatsheetseries.owasp.org
  4. RFC 9116: security.txt rfc-editor.org
  5. nginx: add_header (ngx_http_headers_module) nginx.org
  6. nginx: server_tokens (ngx_http_core_module) nginx.org

Check your security headers

Enter your site address. The report shows each header with the value we saw and what to add. Free, no sign-up, read-only.

Only check sites you own or are allowed to test. How our scanner works