How to set up security headers in a web application

To set up security headers in a web application, send six response headers from your server or CDN: Content-Security-Policy, Strict-Transport-Security, X-Content-Type-Options, X-Frame-Options, Referrer-Policy and Permissions-Policy. Start with the one-line headers that rarely break anything, roll out HSTS and CSP in stages, then confirm what your site actually sends with a free checker. A clean result covers your browser-side defenses only, so this guide also shows what a header check cannot see.
What security headers are and why they matter
An HTTP security header is a response header that helps protect web applications[1]. Your server sends it with a page, and the browser uses it to decide how to treat that page's content: which scripts may run, whether the page may be framed, whether the connection must use HTTPS. OWASP describes these as response headers your application can use to increase its security[2].
Headers are a layer of defense, not a repair. Snyk frames response headers as both potential attack vectors and opportunities for extra layers of defense[3]. They limit what an attacker can do in a visitor's browser. They do not change how your own code handles requests.
The work is small. OWASP calls HTTP headers a great booster for web security with easy implementation[4]. That applies to any web app on any framework, because the headers are plain HTTP and the browser enforces them. A side project needs them as much as an enterprise portal does.
They are also easy to skip when an app goes from prompt to production in an afternoon.
For a concrete case of a fast-build platform under security pressure, read what actually happened in the Replit security breach.
Which security headers are current and which are deprecated
Six headers make up a current baseline: Content-Security-Policy, Strict-Transport-Security, X-Content-Type-Options, X-Frame-Options, Referrer-Policy and Permissions-Policy. Three older ones should stay out of a new configuration: X-XSS-Protection, Expect-CT and Public-Key-Pins. OWASP's cheat sheet says X-XSS-Protection can, in some cases, create XSS vulnerabilities in otherwise safe websites, and that Public-Key-Pins was removed from Chromium in 2018 and is unsupported by all modern browsers[4].
Many header lists online are old and still present the deprecated headers as recommendations. The OWASP Secure Headers Project is the reference to trust, and its project page points to its GitHub repository for the current list[2].
The starting values in the table are conservative defaults, not a finished policy. Check each one against the OWASP HTTP Headers Cheat Sheet before you ship it[4].
| Header | What it controls | Starting value | Status |
|---|---|---|---|
| Content-Security-Policy | Which sources the browser may load content from | default-src 'self', then add trusted sources | Current |
| Strict-Transport-Security | Whether the browser must use HTTPS for the site | max-age with a short lifetime first, longer once stable | Current |
| X-Content-Type-Options | Whether the browser may guess a file's content type | nosniff | Current |
| X-Frame-Options | Whether other sites may embed your pages in a frame | DENY | Current, with CSP frame-ancestors as the alternative |
| Referrer-Policy | How much of the referring URL is sent with outgoing requests | strict-origin-when-cross-origin | Current |
| Permissions-Policy | Which browser features the page may use | geolocation=(), camera=(), microphone=() | Current |
| X-XSS-Protection | A legacy browser XSS filter | Do not enable | Discouraged |
| Expect-CT | Legacy certificate transparency enforcement | Do not set | Deprecated |
| Public-Key-Pins | Legacy certificate pinning | Do not set | Deprecated |
How to set each header on your server
Add the headers in one place that every response passes through: your web server config, your CDN or hosting platform's header settings, or a middleware in your framework. Set the low-risk headers first, then roll out the two that can break things, HSTS and CSP, in stages.
1. X-Content-Type-Options and X-Frame-Options. Both are one-line settings. Send X-Content-Type-Options with the value nosniff. Send X-Frame-Options with the value DENY unless your own pages need to be framed. Sites use this header to avoid clickjacking attacks, by ensuring their content is not embedded into other sites[4]. The frame-ancestors directive in a Content-Security-Policy does the same job if you prefer to manage framing there.
2. Referrer-Policy and Permissions-Policy. These are the easiest to add because they rarely affect how your pages work. Choose a referrer policy that stops full URLs from leaking to other sites, and switch off the browser features your app never uses.
3. Strict-Transport-Security. This header forces all communication between the browser and server to occur over HTTPS connections[3]. Snyk notes that it protects applications from MITM attacks, data leakage and clickjacking[3]. It needs a max-age value, and browsers remember it for that long. Begin with a short lifetime, confirm that every page and subdomain works over HTTPS, and only then lengthen it and add includeSubDomains or preload.
4. Content-Security-Policy. This header lets you control the resources the browser is allowed to load for a given page, which helps guard against cross-site scripting attacks[5]. OWASP describes it as a way to specify the origin of content[4]. Write it to block by default: Snyk's advice is to stick with policies that block activity rather than allow it whenever possible[3]. In practice that means a strict default, plus a named entry for each script, style, image and API host you rely on. Avoid broad wildcards, since they allow the very sources the policy exists to keep out.
CORS headers such as Access-Control-Allow-Origin often get grouped with this list, but they solve a different problem: which other origins may read your responses. If a scanner has flagged yours, see how a CORS misconfiguration CVSS score is decided.
How to check your security headers for free
The quickest check is securityheaders.com: enter your URL and it analyzes the response headers your site returns and grades them. The tool is part of Snyk and was originally created by Scott Helme[6]. It is described as a free and easy to use tool designed to help you better deploy and understand modern security features[6].
You can also look yourself, with nothing to install:
- Browser devtools. Open the Network tab, reload the page, click the main document request and read the response headers.
- Command line. Run curl -I against your URL to print the response headers.
Any of these methods reads the headers on one response to one request. If a CDN or caching layer sits in front of your app, the result shows what that layer sends, which may not match your origin server. Routes can differ as well: a marketing page, an authenticated dashboard and an error page may each go through different config. Check a few representative URLs, including one behind login, and not only the homepage.
What a security headers check does not tell you
A headers check tells you what your server instructs the browser to do. It tells you nothing about what your application does with a request. A top grade can sit on an app where any logged-in user can open another user's records, because that flaw lives in your code and never appears in a response header.
The gaps a header check cannot see fall into a few groups:
- Broken access control. Whether users can access resources or perform actions beyond their permissions, including an admin-only endpoint that answers a logged-out visitor.
- Business logic flaws. Price manipulation, race conditions, workflow bypasses and parameter tampering.
- Cross-site scripting in the app itself. A Content-Security-Policy limits the damage, but reflected, stored and DOM-based XSS still have to be found and fixed.
- JWT handling. Weak signing algorithms, missing expiration claims and improper validation.
Finding these takes a tool that uses the app the way people do. BattleTester crawls your entire application as each user role - anonymous, logged-in and admin - and runs tests for each of the four groups above. Treat that as the step after your headers are fixed, not a replacement for them. Our earlier post covers in more detail what a security headers check tells you and what it misses.
Two things to know before you start. A full pentest costs $15 and is charged only if the scan finds High or Critical vulnerabilities. Scans also run against the live app, log in like a real user and will likely create test data, so point them at an environment you can restore or use a throwaway account.
FAQ
What is a security headers check?
It is a test that requests a URL and reports which HTTP security headers the response includes, which are missing and which are set weakly. It takes seconds and needs no access to your code or accounts.
Do security headers apply to APIs the same way as web pages?
Security headers are HTTP response headers, so an API can send them too. Which ones matter depends on whether a browser ever renders the response, so do not copy a web page configuration blindly. Work through the OWASP guidance for your own setup[4].
How do I set Content-Security-Policy without breaking my site?
Send the policy as Content-Security-Policy-Report-Only first. The browser then reports what the policy would block without blocking it, so you can add the sources you missed before you switch to the enforcing header.
What's the difference between a header check and a full penetration test?
A header check reads one response and compares its headers to a list. A penetration test sends crafted requests as different users to find flaws in how the app behaves. Automated testing has limits too: BattleTester is not a comprehensive security audit and does not replace a professional security assessment by qualified security professionals.
Sources
- What is a HTTP security header?, Acunetix, accessed October 11, 2026
- OWASP Secure Headers Project, OWASP, accessed October 11, 2026
- Security implications of HTTP response headers, Snyk (dev.to), accessed October 11, 2026
- HTTP Headers Cheat Sheet, OWASP, accessed October 11, 2026
- Content-Security-Policy header, MDN Web Docs (Mozilla), accessed October 11, 2026
- securityheaders.com tool profile, PentestReports, accessed October 11, 2026