Home / Guides

How to add security headers on Netlify

Add CSP, HSTS, X-Frame-Options and other security headers on Netlify using a _headers file or netlify.toml. Copy-paste examples, framework tips and testing.

Updated 2026-10-15 · ShipCheck guides

Netlify serves your site over HTTPS, but out of the box it doesn't send most of the security headers that browsers use to block XSS, clickjacking and MIME sniffing. You can add them in two ways, a _headers file or netlify.toml, and neither needs a code change.

Option A: the _headers file

Create a plain-text file named _headers (no extension) that ends up in your publish directory. For Vite, CRA and most static generators, put it in public/ so it is copied into dist/ or build/.

/*
  Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
  X-Content-Type-Options: nosniff
  X-Frame-Options: DENY
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: camera=(), microphone=(), geolocation=()
  Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'

The first line is the path pattern (/* means every page). Header lines underneath must be indented.

Option B: netlify.toml

[[headers]]
  for = "/*"
  [headers.values]
    Strict-Transport-Security = "max-age=63072000; includeSubDomains; preload"
    X-Content-Type-Options = "nosniff"
    X-Frame-Options = "DENY"
    Referrer-Policy = "strict-origin-when-cross-origin"
    Permissions-Policy = "camera=(), microphone=(), geolocation=()"
    Content-Security-Policy = "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'"

netlify.toml lives in the repository root (or your base directory), not in the publish folder.

What these headers protect against

Tuning CSP for common services

Add the origins your app actually uses:

To avoid breaking production, ship the policy as Content-Security-Policy-Report-Only first, browse the whole app with devtools open, fix the violations it reports, and then switch to the enforcing header. If your framework relies on inline scripts and you can't add nonces or hashes, you may need 'unsafe-inline' in script-src. That is weaker, but the other directives still help.

Different headers for different paths

/*
  X-Frame-Options: DENY

/embed/*
  X-Frame-Options: SAMEORIGIN

When several rules match, Netlify combines them. If the same header appears more than once, the values are merged into a comma-separated list rather than replaced. For security headers that rarely gives the result you want, so give each header exactly one definition per path.

Common gotchas

Verify

curl -sI https://yoursite.netlify.app | grep -iE "strict-transport|content-security|x-frame|x-content-type|referrer|permissions"

Or paste your URL into ShipCheck for a free header and HTTPS check with fixes. On Vercel instead? See security headers on Vercel.

Scan your app free

Paste your live URL or public GitHub repo. ShipCheck checks for leaked keys, committed .env files, missing security headers, HTTPS issues and slow pages, then gives you copy-paste fixes. No signup.

FAQ

Where does the Netlify _headers file go?

In your publish directory, the folder that gets deployed, such as dist, build or public for Vite and CRA. If it is not in the deployed output, Netlify ignores it. Putting it in public/ usually gets it copied into the build.

_headers or netlify.toml: which should I use?

Both work. _headers is simpler. netlify.toml keeps all config in one file. Don't define the same header for the same path in both.

Do Netlify headers apply to Netlify Functions?

Custom headers from _headers and netlify.toml apply to static files only, not to responses from Functions or Edge Functions. Set headers on function responses in your function code.

More guides

Is my Lovable app secure?

How to check whether your Lovable app is secure: Supabase Row Level Security, exposed keys, security headers, auth and storage. A step-by-step checklist with fixes.

How to add security headers on Vercel

Copy-paste vercel.json to add CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy and Permissions-Policy on Vercel, plus how to test them.

The vibe-coded app launch checklist

A practical pre-launch checklist for apps built with Lovable, Cursor, Bolt, v0 or Replit: security, secrets, database rules, performance, SEO, legal and monitoring.

Exposed .env file or API key? How to check and rotate

How to find leaked API keys and committed .env files in your repo, JavaScript bundle or live site, rotate them safely, and stop it happening again.