📋 HTTP security header checks explained

Every response-header check of the headers module: what is tested, why it matters and how it is scored – from HSTS and CSP quality down to cookie flags and information leaks. Check your domain →

Last updated: July 2026 · 31 checks documented

HTTP response reachable #

The header checks evaluate the response of a real page load (https://…/). If no HTTP response can be fetched – connection refused, timeout, or an invalid certificate aborting the request – there are no headers to grade.

RatingOnly appears when the page load fails: skip; the module is reported as not gradeable instead of being graded F on missing data.
How to fix itMake sure the site answers HTTPS requests with a valid certificate and within a reasonable time, then re-run the scan. The Website module usually shows the underlying TLS problem in detail.

Redirect target #

The scanner follows redirects before analyzing headers. If the chain ends on a different domain, all header findings describe that final host, not the scanned domain. If it ends on unencrypted http://, the entire page (content, cookies, logins) is exposed to man-in-the-middle attacks despite the HTTPS start.

Ratingfail + Cap C if the final URL is http:// (HTTPS→HTTP downgrade); info if the redirect merely ends on another registrable domain. Not shown when the page stays on the scanned domain over HTTPS.
How to fix itRemove any redirect to http:// and serve the final page over HTTPS. For cross-domain redirects, scan the final domain directly for meaningful results.

Strict-Transport-Security (HSTS) #

HSTS instructs the browser to access the domain exclusively over HTTPS from then on, preventing SSL-stripping/downgrade attacks as well as insecure first visits.

Ratingpass with max-age ≥ 1 year; warn with a shorter lifetime; missing → fail. Special case: max-age=0 → fail, because that actively DELETES an existing HSTS policy in the browser. Weight 2.
How to fix itSet the header: Strict-Transport-Security: max-age=63072000; includeSubDomains; preload (only after HTTPS is verified on all subdomains).

HSTS preload #

Domains on the browsers’ HSTS preload list are addressed only over HTTPS from the outset – even on the very first visit, before any header is seen. This point checks two independent facts: (1) eligibility – does the current header meet the hstspreload.org criteria (max-age ≥ 1 year, includeSubDomains, preload)? and (2) list status – is the domain actually on the preload list, queried live from the official hstspreload.org status API? The critical case is being on the list while the header is no longer compliant (e.g. preload was removed later): shipping browsers still enforce HTTPS, but the entry becomes eligible for automatic removal – after which first-visit protection silently disappears – and the header should never have been changed without the official removal process.

Ratinggood when preloaded with a still-compliant header, or eligible-but-not-yet-submitted (submitting is optional, weight 0); info when not preloaded and not yet eligible; warn (weight 1) for a pending submission/removal whose header no longer matches; fail (weight 2) when the domain is on the preload list but the current header is non-compliant.
How to fix itTo get preloaded: meet all criteria and submit at hstspreload.org. If already preloaded, keep serving max-age=63072000; includeSubDomains; preload unchanged; to leave the list, use hstspreload.org/removal/ rather than just dropping the header.

Content-Security-Policy #

The CSP is the most effective protection layer against cross-site scripting (XSS): it defines which sources may load scripts, styles, etc. A pure host allowlist with unsafe-inline is often bypassable; nonce-/hash-based policies with strict-dynamic are strong. The detail additionally reports whether the strict internet.nl criteria are met (no unsafe source in ANY directive incl. style-src, no http:/bare https:/wildcard hosts, restricted default-src/frame-ancestors/base-uri/form-action) – relevant for a 100% internet.nl score, without influence on the grade here.

Ratingpass with a strong (nonce/hash) CSP or an allowlist without unsafe sources; warn with unsafe-inline/wildcards without nonce or Report-Only only; fail if no CSP is set. Weight 2.
How to fix itUse a nonce-/hash-based CSP with strict-dynamic; avoid unsafe-inline/unsafe-eval (inline styles → CSS files or element.style/CSSOM).

CSP hardening (object-src / base-uri / form-action) #

Three directives harden a CSP against injection beyond script sources: object-src 'none' blocks outdated plugin embeddings (<object>/<embed>). base-uri and form-action have NO fallback to default-src – without them set, an injected <base> tag can redirect relative URLs to a foreign server, and an injected <form action> can send data to foreign servers (phishing/exfiltration), even with a strict default-src.

Ratingpass if all three are restricted (object-src/default-src 'none'; base-uri 'none'/'self'; form-action 'self'/'none'); otherwise warn listing the missing directives. Only with an enforced CSP. Weight 2.
How to fix itAdd object-src 'none'; base-uri 'none'; form-action 'self' to the CSP.

CSP upgrade-insecure-requests #

Automatically upgrades insecure HTTP resource requests to HTTPS, thereby preventing mixed content. The older block-all-mixed-content is deprecated.

RatingInformational (weight 0): indicates whether the directive is active.
How to fix itAdd upgrade-insecure-requests to the CSP (replaces block-all-mixed-content).

CSP Trusted Types #

Trusted Types (require-trusted-types-for 'script') are the strongest protection layer against DOM-based XSS: dangerous DOM sinks then accept only vetted values.

RatingPositive info signal (weight 0) – no deduction if missing (advanced).
How to fix itOptionally set require-trusted-types-for 'script' (+ trusted-types).

CSP sandbox #

The sandbox directive additionally restricts the document (like the iframe sandbox attribute). Caution: allow-scripts + allow-same-origin together largely defeat the sandbox.

Ratinggood if restrictive; warn with allow-scripts + allow-same-origin. Weight 0.
How to fix itDo not allow allow-scripts and allow-same-origin together.

CSP violation reporting #

CSP violations can be reported – in the modern form via report-to <group> (references a defined reporting endpoint), in the deprecated form via report-uri <url>. If report-to references an undefined group, all reports are silently lost.

Ratingpass with a valid report-to; warn with report-to pointing to an undefined endpoint; info if only the deprecated report-uri is used. Weight 0.
How to fix itSet report-to to a group defined in Reporting-Endpoints (add report-uri as well for the transition).

X-Content-Type-Options: nosniff #

Prevents MIME sniffing – the browser then interprets responses strictly according to the declared Content-Type instead of "guessing", which blocks certain XSS tricks.

Ratingpass with nosniff; otherwise fail. Weight 1.
How to fix itSet the header: X-Content-Type-Options: nosniff.

Clickjacking protection #

Prevents the page from being embedded in a foreign frame and abused for clickjacking – via X-Frame-Options or, in the modern form, via CSP frame-ancestors.

RatingThe VALUE counts: pass with DENY/SAMEORIGIN or CSP frame-ancestors with none/self/host allowlist; warn with ALLOW-FROM (ignored by modern browsers) or frame-ancestors */scheme wildcard; fail if both are missing. Weight 1.
How to fix itSet X-Frame-Options: DENY or CSP frame-ancestors 'none' (frame-ancestors is the modern, more powerful option).

Referrer-Policy #

Controls how much of the originating URL is sent to third parties when leaving the page. Some values are unsafe: unsafe-url always sends the full URL, and no-referrer-when-downgrade leaks it on an HTTPS→HTTP downgrade.

RatingThe VALUE counts (not just its presence): pass with no-referrer / same-origin (fully privacy-protecting) as well as strict-origin / strict-origin-when-cross-origin (pass with a tightening recommendation – internet.nl rates these two as recommendation-level only); warn with origin / origin-when-cross-origin / no-referrer-when-downgrade / unsafe-url or a missing header. With multiple (fallback) values, the last one understood by the browser counts. Weight 1.
How to fix itSet Referrer-Policy: no-referrer or same-origin; strict-origin-when-cross-origin is an acceptable minimum.

Permissions-Policy #

Selectively disables powerful browser features (camera, microphone, geolocation …) and reduces the attack surface – including for embedded content. Allowlist syntax: () = off, self = own domain only, * = everywhere (risk), (self "https://…") = allowlist.

Ratingpass if the core features (camera/microphone/geolocation/payment/usb) are disabled; warn with wildcard * on a core feature, a missing header, empty/permissive values, or outdated Feature-Policy syntax. Additional high-risk features (display-capture, serial, hid, bluetooth …) are also listed. Weight 1.
How to fix itSet unneeded features to (), e.g. Permissions-Policy: camera=(), microphone=(), geolocation=().

Cross-origin isolation (COOP/COEP) #

COOP isolates the browsing context from cross-origin opened windows and makes XS-Leaks harder. The value is decisive: unsafe-none provides no protection. FULL cross-origin isolation (for SharedArrayBuffer/precise timers) additionally requires COEP require-corp/credentialless; CORP protects your own resources from being included by foreign sites. The COEP/CORP state is reported as context in the same finding – it is optional for many sites and potentially breaking.

RatingInformational only – NOT graded. COOP/COEP/CORP are emerging headers: securityheaders.com lists them as "Upcoming", Mozilla Observatory does not score them and internet.nl does not test them, and requiring COOP same-origin can break OAuth/payment popups on ordinary sites. A protective COOP value (same-origin/same-origin-allow-popups) earns a green check (good); unsafe-none or a missing header is neutral info. Neither affects the grade. COEP/CORP are reported as context.
How to fix itOptional hardening only. Set Cross-Origin-Opener-Policy: same-origin if you rely on cross-origin isolation (SharedArrayBuffer, precise timers); for full isolation additionally Cross-Origin-Embedder-Policy: require-corp and appropriate CORP headers. Not required for a typical site.

Origin-Agent-Cluster #

With Origin-Agent-Cluster: ?1, the page asks the browser to place it in an origin-isolated process. This makes Spectre-style side-channel attacks between origins harder.

RatingInformational (weight 0) if set.
How to fix itOptionally set Origin-Agent-Cluster: ?1.

Document-Policy #

Document-Policy controls document-wide features (e.g. enforced image compression, oversized images) – related to the Permissions-Policy, but for document properties.

RatingInformational (weight 0) if set.
How to fix itOptionally use it depending on the use case.

Mixed Content #

If an HTTPS page loads resources over http://, an attacker can tamper with them. Active mixed content (scripts/iframes/CSS) allows takeover of the page, while passive content (images) is often blocked.

Ratingactive mixed content → fail; passive → warn; none → pass. upgrade-insecure-requests counts as a mitigation. Weight 1–2.
How to fix itInclude all resources over HTTPS or set CSP upgrade-insecure-requests.

Subresource Integrity (SRI) #

Cross-origin included scripts/styles (e.g. from CDNs) without an integrity hash are vulnerable to supply-chain tampering: if the CDN is compromised, attacker code runs on the page.

Ratingpass if cross-origin scripts carry an integrity attribute; otherwise warn. Weight 1.
How to fix itAdd integrity="sha384-…" crossorigin="anonymous" to cross-origin <script>/<link>.

Integrity-Policy #

Enforces Subresource Integrity (SRI) for included resources – strong supply-chain protection that goes beyond the individual integrity attribute.

RatingPositive info signal (weight 0) – no deduction if missing (new header).
How to fix itOptionally set Integrity-Policy: blocked-destinations=(script).

Cookie security attributes #

Cookies without Secure can be intercepted over HTTP; without HttpOnly they can be read via JavaScript (XSS); SameSite protects against CSRF.

Ratingpass if all set cookies carry Secure + HttpOnly; otherwise warn. Weight 1.
How to fix itServe cookies with Secure; HttpOnly; SameSite=Lax (or Strict).

Cookie name prefixes (__Host-/__Secure-) #

The name prefixes __Host- and __Secure- (RFC 6265bis) let the browser enforce cookie integrity: a __Secure- cookie must be set with Secure, a __Host- cookie additionally with Path=/ and without a Domain attribute. Violating cookies are silently discarded by browsers – the application then never receives them, which surfaces as mysterious login loops.

Ratingwarn when a prefixed cookie violates its preconditions. Weight 1. Correctly used prefixes are simply part of a pass in the cookie check.
How to fix itSet Secure (and for __Host-: Path=/, no Domain=) – or use the prefix deliberately: __Host-session=…; Secure; HttpOnly; SameSite=Lax; Path=/ is the most robust session-cookie form.

Cache-Control on authenticated responses #

Authenticated responses (with a session/auth cookie) should not be cached in proxies/browsers – otherwise subsequent users could see other people’s logged-in content.

Ratinginfo (weight 0): checked ONLY if a session/auth cookie is set and the response is not no-store/private (to avoid false positives on public pages).
How to fix itServe authenticated responses with Cache-Control: no-store (or private).

CORS (Access-Control-Allow-Origin) #

A misconfigured CORS policy can allow foreign sites to read authenticated responses. A reflected (or *) origin combined with Access-Control-Allow-Credentials: true is dangerous.

Ratingfail with a reflected/* origin + credentials (reading authenticated data possible); info with * without credentials (usually fine for public assets). Only checked if ACAO is set.
How to fix itNever combine a reflected origin/* with Allow-Credentials: true; use a strict origin allowlist instead.
Sources: MDN: CORS ↗

X-Permitted-Cross-Domain-Policies #

Controls whether Adobe clients (Flash/Acrobat) may access across domains via crossdomain.xml. Best practice is none. Real-world relevance is low (Flash is dead), but it is checked by scanners like securityheaders.com.

Ratingpass with none; warn with all; info for any other value (e.g. master-only). Only evaluated when the header is set. Weight 0.
How to fix itOptionally set X-Permitted-Cross-Domain-Policies: none.

X-XSS-Protection (deprecated) #

The browsers’ former XSS auditor has been removed and could itself cause security problems (XS-Leaks). The header should no longer be used actively.

Ratinginfo (weight 0) if set to 1/1; mode=block – recommendation to remove it or set it to 0.
How to fix itSet the header to 0 (or remove it) and use a CSP instead.

HTTP Public Key Pinning (HPKP) #

HPKP was meant to prevent certificate mis-issuance, but it was so dangerous (risk of permanently locking yourself out) that it was removed from all browsers.

Ratingwarn (weight 1) if Public-Key-Pins(-Report-Only) is set – the header should be removed.
How to fix itRemove the HPKP header (use Certificate Transparency + CAA instead).

Expect-CT (deprecated) #

The Expect-CT header has been removed since Chrome 107 – Certificate Transparency is now enforced automatically. The header is superfluous.

RatingInformational (weight 0).
How to fix itRemove the Expect-CT header.

Violation/error reporting #

Reporting delivers reports about CSP/COOP/network violations. There are two generations: Reporting-Endpoints (modern, preferred) and the deprecated Report-To (deprecated by Chrome). Important: NEL (Network Error Logging) works ONLY with Report-To, not with Reporting-Endpoints.

Ratinginfo (weight 0): distinguishes modern/legacy/NEL. warn if NEL references a Report-To group that is not defined (reports are silently lost). Deprecated Report-To only → note about migrating.
How to fix itSet Reporting-Endpoints; for NEL, additionally define a matching Report-To group.

Technology disclosure (Server / X-Powered-By) #

Headers like Server: nginx/1.26.3 or X-Powered-By: PHP/8.2 reveal the software stack. A version number lets an attacker match known CVEs directly to the exact build – that is what matters and what gets downgraded. A bare product name (Server: nginx, AmazonS3, cloudflare, Apache) only says WHAT runs, not which version, so it cannot be mapped to a specific CVE and is treated as purely informational (no downgrade). A "version" means a dotted decimal (e.g. /1.26.3, 4.0.30319); a product name that merely contains a digit (AmazonS3, CDN node IDs) is not a version. Hiding banners entirely is hygiene (minimal disclosure), not a substitute for patching.

Ratinggood when no technology headers are sent; info with product names only, even when the name contains a digit like AmazonS3 (weight 0, no downgrade); warn only when an actual version number (dotted decimal) is disclosed (weight 1). Checked: Server, X-Powered-By, X-AspNet-Version, X-AspNetMvc-Version, X-Generator.
How to fix itnginx: server_tokens off (hides the version) or remove entirely with the headers-more module (more_clear_headers Server); Express: app.disable("x-powered-by"); PHP: expose_php = Off.

security.txt (RFC 9116) #

A /.well-known/security.txt provides contact channels for security reports and facilitates responsible disclosure of vulnerabilities. The file is validated against the MUST/SHOULD requirements of RFC 9116 the way internet.nl’s sectxt validator does: mandatory Contact (as a URI – a bare email address without mailto: is invalid, §2.5.3), exactly one Expires in RFC 3339 format that is not in the past (§2.5.5), text/plain with UTF-8 (§3), https:// for all web URIs, valid field syntax, at most one Preferred-Languages with valid tags, the mandatory /.well-known/ location (§3) and – if Canonical is present – that the retrieved URI is listed there (§2.5.2, otherwise the file should not be trusted). SHOULD requirements (Expires less than a year ahead, OpenPGP signature, Encryption key for email contacts) are reported as hints; the signature is checked structurally, not cryptographically.

Ratinggood if present and the validation reports no errors (open recommendations are listed as hints); warn as soon as at least one error-class issue is found – the same severity split internet.nl uses; info if missing. Weight 0.
How to fix itProvide a file at /.well-known/security.txt with Contact: (mailto:/tel:/https: URI) and Expires: (RFC 3339, less than a year ahead), served as text/plain; charset=utf-8; if Canonical is used, list the exact retrieval URI. Validate e.g. with the internet.nl security.txt check.

← All checks & scoring methodology