A site can have a clean codebase, a solid TLS certificate, and still ship with a set of missing HTTP response headers that leave it wide open to clickjacking, content sniffing, or a weak Content Security Policy that does nothing. Headers are easy to skip because nothing visibly breaks when they're missing. The page loads, the API responds, everything looks fine right up until someone tests the actual security posture instead of just the functionality.
Why This Gets Skipped So Often
Header configuration doesn't touch application logic, doesn't appear in most functional test suites, and doesn't break anything a user would notice during normal browsing. That combination makes it one of the easiest categories of work to postpone indefinitely, especially under a deadline where visible functionality understandably takes priority. The gap between "nothing looks broken" and "this is actually secure" is exactly where headers live, and it's a gap that only shows up once someone specifically goes looking for it, whether that's a security review, a penetration test, or an actual attacker.
Step 1: Pull the Raw Response Headers
Before fixing anything, see what's actually being sent. A quick request against the live endpoint, whether through a browser's network tab or a command-line request, shows every header the server is currently returning. Do this against the real production configuration, not local development, since proxies, load balancers, and CDN layers frequently add or strip headers between your app server and the actual response a browser receives.
Step 2: Check for the Core Set That Actually Matters
A handful of headers cover most of the practical risk. Strict-Transport-Security tells browsers to only ever connect over HTTPS for that domain going forward, closing a downgrade attack window. X-Content-Type-Options: nosniff stops browsers from guessing at a file's type in a way that can be abused to execute something that shouldn't run. X-Frame-Options or the frame-ancestors directive in a Content Security Policy prevents your page from being embedded in a hidden iframe on someone else's site for clickjacking. Referrer-Policy controls how much of your URL leaks to external sites when a user clicks a link away from your page.
Step 3: Build a Content Security Policy That Isn't Just unsafe-inline Everywhere
CSP is the header most likely to be either missing entirely or configured so loosely it provides almost no protection. A policy padded with unsafe-inline and unsafe-eval across every directive technically satisfies "we have a CSP" while doing very little to actually restrict what can execute on the page. The OWASP Cheat Sheet Series has a dedicated entry on building a CSP incrementally, starting in report-only mode so you can see what would have broken before actually enforcing it.
Step 4: Confirm Cookie Flags Separately From Headers
Cookies carry their own security-relevant flags that don't show up in the general header list unless you're specifically checking the Set-Cookie line. Secure ensures a cookie only transmits over HTTPS. HttpOnly blocks client-side JavaScript from reading it, which matters a lot for session cookies. SameSite controls whether the cookie gets sent along with cross-site requests, directly affecting CSRF exposure. All three are cheap to add and each closes a distinct, real attack path.

Photo by Vladimir Srajber on Pexels
Step 5: Test Against a Grading Tool, Not Just a Manual Checklist
Manually checking a dozen headers against a mental list is error-prone, especially across multiple environments or services. Running the response through a grading tool surfaces what's missing, what's misconfigured, and what's actually solid, all in one pass. The HTTP Security Header Grader at EvvyTools grades a pasted set of response headers across eight categories including CSP, HSTS, frame options, content type options, referrer policy, permissions policy, and cookie flags, returning a letter grade per category instead of a single pass-or-fail verdict that hides which specific header needs attention.
Step 6: Recheck After Every Infrastructure Change
Headers that were correctly configured at the application layer can get silently stripped or overridden by a CDN, a reverse proxy, or a load balancer added later. A header audit that passed at launch doesn't stay valid forever if anything sits between the app and the browser gets touched. Treating this as a one-time launch checklist item rather than something to recheck after infrastructure changes is one of the most common ways a previously solid configuration quietly regresses.
Step 7: Reference the Actual Spec When a Header's Behavior Is Ambiguous
Header documentation across the web varies in quality, and some of it is outdated or describes browser behavior that's since changed. MDN's HTTP headers reference stays current with actual browser support and is the most reliable place to confirm exactly what a given directive does and which browsers respect it, rather than trusting a blog post that might be several years old.
Step 8: Don't Treat Every Environment the Same Way
Staging and production often need different header configurations, and copying one environment's headers onto another without thinking it through causes its own problems. A CSP tuned for a staging environment with relaxed rules for debugging tools can accidentally ship to production if the configuration isn't environment-aware, quietly weakening the exact protection the header was supposed to provide. Conversely, a strict production CSP copied onto staging can break debugging tools that engineers actually rely on day to day. Keeping the header configuration explicitly scoped per environment, rather than assuming one file covers everything, avoids both failure modes.
Step 9: Understand What Each Missing Header Actually Costs You
It's worth being specific about what's at stake rather than treating "add security headers" as a vague best practice. A missing X-Frame-Options or frame-ancestors directive leaves a page embeddable in an invisible iframe on an attacker's site, where a user thinks they're clicking something on the visible page but their click actually lands on a hidden, malicious layer underneath. A missing or weak CSP does little to stop injected scripts from running if an XSS vulnerability exists elsewhere in the application, turning what should be a contained bug into something an attacker can fully exploit. A missing Strict-Transport-Security header leaves a narrow window on the very first connection where a downgrade to plain HTTP is technically possible. None of these are hypothetical categories, they map to specific, well-documented attack techniques that security researchers actively test for.
Step 10: Automate the Check So It Can't Get Skipped Silently
The most durable fix for a check that's easy to forget is removing the human "remember to do this" step entirely. Wiring a header check into a deploy pipeline, failing the build or at least flagging a warning when a required header is missing or a grade drops below a set threshold, turns this from a manual habit someone might forget under deadline pressure into something that simply can't ship silently broken. This is a bigger lift than a one-time manual check, but for anything deploying regularly, it's the difference between headers staying correct indefinitely and headers slowly drifting out of configuration the first time nobody happens to remember to check.
The Payoff for a Few Minutes of Work
None of these headers require touching application logic or redesigning anything. They're configuration, usually a handful of lines in a server block, a middleware function, or a CDN rule set. The OWASP Secure Headers Project maintains ongoing guidance on this exact topic if you want a broader reference beyond the cheat sheet series, since header best practices shift as new attack techniques and browser features get standardized.
Running a fresh grade on every environment, staging included, before anything goes live catches the gaps while they're still cheap to fix. And if the server in question sits behind infrastructure defined by IP ranges and subnets you're actively managing, the guide on how subnet masks and CIDR blocks actually get calculated covers the addressing side of that same infrastructure planning.
Top comments (0)