Responses lack the HTTP headers that switch on browser protections: Content-Security-Policy, Strict-Transport-Security, X-Content-Type-Options, a frame policy (frame-ancestors or X-Frame-Options) and a Referrer-Policy. None of them is a vulnerability alone; they are defence in depth.
At a glance
- Why it matters
- Without them other weaknesses become easier to exploit: clickjacking works, an XSS bug has no CSP to stop it, a first visit can be downgraded to plain HTTP and browsers may sniff an upload as HTML. Missing headers are also a quick signal to attackers that hardening was skipped.
- How to fix it
- Set the headers once at the edge (reverse proxy or framework middleware) so every response carries them. Start with HSTS, nosniff, frame-ancestors 'none' and a report-only CSP, then tighten the CSP. Check the result with our HTTP Header Analyser.
Description
Modern browsers support a set of HTTP response headers that constrain what a page is allowed to do: Content-Security-Policy restricts where scripts and other resources can load from, X-Frame-Options and frame-ancestors control whether the page can be embedded in another site's frame, X-Content-Type-Options stops the browser guessing a file's type, Strict-Transport-Security forces HTTPS for future visits, and several others narrow what a page can access or how cookies behave. Their absence is not itself an exploit; it removes a layer of defence that limits how far other findings (particularly XSS and clickjacking) can go.
Impact
Missing headers widen the blast radius of other issues rather than being independently catastrophic on their own. Without a restrictive CSP, an XSS payload that would otherwise be constrained can load and execute a remote script freely. Without X-Frame-Options or frame-ancestors, the page can be embedded in an attacker's site and used for clickjacking, tricking a logged-in user into clicking something they cannot see. Missing HSTS leaves the very first connection of a session vulnerable to being silently downgraded to plain HTTP by a network attacker.
How we find it
- Our HTTP Header Analyser automates the first part of this check: it fetches the page and grades HSTS, CSP, X-Frame-Options/frame-ancestors, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, COOP, and cookie attributes.
- We check that a present CSP is actually restrictive; a CSP that allows
unsafe-inlineor a wildcard script source is technically present but provides little of the protection a CSP is meant to add. - We verify headers are applied consistently across every route, not only the homepage; a security header set at the edge for one path and missed on an API or admin route is a common gap.
Fix
Set explicit values for HSTS, Content-Security-Policy, X-Frame-Options or frame-ancestors, X-Content-Type-Options and Referrer-Policy at the web server or application framework level, applied globally rather than per route, so a new route inherits the baseline by default instead of needing to opt in.
# nginx: a reasonable starting baseline, tune the CSP to your actual sources
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; frame-ancestors 'none'" always;
References
- OWASP Secure Headers Project
- CWE-693: Protection Mechanism Failure
- MDN: HTTP security-related response headers