Security headers: nosniff, Referrer-Policy, Permissions-Policy and X-Frame-Options
Besides HSTS and CSP, a handful of smaller headers each close one specific gap with a single line of configuration. Others still sit in many templates long after browsers stopped paying attention to them.
Updated: 05 November 2026
X-Content-Type-Options
Browsers sometimes guess what kind of file a response really contains. That MIME sniffing turns into a problem once visitors can upload files. A supposed text file that contains HTML may then be rendered as a page, scripts and all.
X-Content-Type-Options: nosniff turns the guessing off. The browser takes the declared type at face value, and it refuses scripts or stylesheets whose type does not fit: scripts need a JavaScript type, stylesheets text/css. There is no other value.
If a script stops loading once the header is in place, the server is probably sending it as text/plain or without any type. Fix the type in the server configuration and keep the header.
Referrer-Policy
When a visitor follows a link, the browser sends a Referer header saying which address they came from. The same goes for images, fonts or scripts your page loads from elsewhere. Paths and query strings give away more than you might think, such as search terms, order numbers or the token in a password reset link.
Without a policy of your own, current browsers apply strict-origin-when-cross-origin (W3C Referrer Policy). Other sites then learn only the origin, meaning scheme, host and port. ZwoWebCheck therefore treats a missing header as a note only. Set it explicitly anyway, because older browsers had a looser default.
| Value | Same origin | Other origin (HTTPS) | Target over HTTP |
|---|---|---|---|
no-referrer |
nothing | nothing | nothing |
same-origin |
full address | nothing | nothing |
strict-origin |
origin | origin | nothing |
strict-origin-when-cross-origin |
full address | origin | nothing |
no-referrer-when-downgrade |
full address | full address | nothing |
unsafe-url |
full address | full address | full address |
The last two hand the complete address to every other site, and unsafe-url does so even over plain HTTP. ZwoWebCheck rates both as medium. no-referrer-when-downgrade was Chrome's default until 2020, which is why older guides still recommend it. If you want to share less than the default, use same-origin or no-referrer.
Permissions-Policy
A Permissions-Policy switches off browser features your site has no use for, such as the camera, microphone or geolocation. A script that reaches the page through a tag manager or a vulnerability can then no longer ask for them, and neither can anything you embed.
The header is a structured field as defined in RFC 9651, with entries separated by commas. () blocks a feature for everyone, (self) allows it for your own origin only, and further origins follow in double quotes:
Permissions-Policy: camera=(), microphone=(), geolocation=(self "https://maps.example.com")
Its predecessor, Feature-Policy, used a different syntax (camera 'none'; microphone 'none'). If that syntax ends up in the new header, the browser cannot parse it and discards the whole policy. Lists copied from the web deserve a second look too, since fullscreen=() takes the full-screen button away from embedded videos.
Only Chromium-based browsers such as Chrome and Edge act on the header so far; Firefox and Safari ignore it. That is why ZwoWebCheck merely checks that it is there and reports a missing one as a note.
X-Frame-Options or frame-ancestors
The CSP article explains clickjacking. There are two ways to defend against it. X-Frame-Options offers DENY, which forbids framing altogether, and SAMEORIGIN, which allows it for your own origin only. The old ALLOW-FROM value makes current browsers ignore the entire header, so ZwoWebCheck counts it as missing.
If a partner needs to embed your page, a booking form for instance, use frame-ancestors in your CSP. It takes precedence when both are present, and either satisfies the check. Neither works in a meta tag, and a CSP in report-only mode does not protect against framing either.
Cross-Origin-Opener-Policy
When your page opens a window, or is opened by one, each side keeps a reference to the other, which a page from another site can use to redirect yours. Cross-Origin-Opener-Policy: same-origin severs that link to other origins. Login and payment pop-ups that report back through window.opener will then break; same-origin-allow-popups exempts windows your own page opens. ZwoWebCheck does not check this header.
Headers you can remove
X-XSS-Protectioncontrolled the XSS filter in older browsers. Chrome dropped its filter in 2019 and Firefox never had one. Attackers could even abuse the filter to switch off selected scripts on a page. Remove the header or set it to0.Expect-CTonly ever worked in Chromium browsers. Chrome deprecated it in version 107, since it now requires Certificate Transparency for every public certificate anyway.Public-Key-Pins(HPKP) tied a domain to particular keys, and one mistake during a certificate change could lock visitors out. Chrome 72 and Firefox 72 removed it. To restrict which certificate authorities may issue for your domain, use CAA.Feature-Policyhas been replaced by Permissions-Policy.
Putting it together
In nginx, the lines go into the server block. Add always so that error pages get them too. The HSTS article explains how add_header in a location block silently drops them.
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;
For Apache with mod_headers, in the VirtualHost or in .htaccess:
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=()"
Common mistakes
- Several values in the wrong order.
Referrer-Policy: strict-origin-when-cross-origin, unsafe-urlends up asunsafe-url, because the last value the browser recognises wins. Put the value you want last and any fallback for older browsers before it. - Headers set by a CMS plugin rather than the web server. Images, PDFs and error pages then go out without them.
Checking security headers
ZwoWebCheck rates this area on the page your request lands on once all redirects are done. Alongside the CSP, the report gives nosniff, clickjacking protection, the Referrer-Policy and the Permissions-Policy a traffic light apiece. Where nosniff or clickjacking protection is missing, or the Referrer-Policy leaks full addresses, you will find the matching configuration line for your web server.