Security headers on Netlify

Clear the header findings on a Netlify site with no server of your own. Set security headers in a _headers file or in netlify.toml, cited to the Netlify docs.

Netlify reads custom response headers from two places: a file named _headers or the netlify.toml configuration file.

The _headers file is plain text in the publish directory. A path goes on one line with its headers indented under it.

_headers

/*
  X-Content-Type-Options: nosniff

In netlify.toml each rule is a [[headers]] table, with the path in for and the headers under [headers.values].

netlify.toml

[[headers]]
  for = "/*"
  [headers.values]
    X-Content-Type-Options = "nosniff"

The examples below use the _headers form. In netlify.toml the same name and value go under [headers.values]. If a build step writes the site, the _headers file has to end up in the folder Netlify deploys. Custom headers apply only to files Netlify serves itself. A proxied response gets none of them. Neither does a response from a function or an edge function, such as a server-rendered page, so that code has to send its own headers. Headers set either way apply to every build and every deploy context alike. Netlify ignores custom values for a short list of headers it sets itself. None of the six headers on this page is on that list.

Source: Netlify docs: custom headers

Strict-Transport-Security (HSTS)

Add Strict-Transport-Security under the path.

_headers

/*
  Strict-Transport-Security: max-age=31536000; includeSubDomains

Add includeSubDomains only when every subdomain answers over HTTPS.

Source: Netlify docs: custom headers

Content-Security-Policy (CSP)

Start with the report-only header under the path.

_headers

/*
  Content-Security-Policy-Report-Only: default-src 'self'

Once the reports show the policy breaks nothing, rename the header to Content-Security-Policy to enforce it.

_headers

/*
  Content-Security-Policy: default-src 'self'

Report-only mode shows what a policy would stop without stopping it. The CSP fix guide linked below builds a working policy that way before it is enforced.

Source: Netlify docs: custom headers

X-Frame-Options

Add X-Frame-Options under the path. Netlify uses this header for its own _headers example.

_headers

/*
  X-Frame-Options: SAMEORIGIN

SAMEORIGIN lets only your own pages frame the site. DENY refuses every frame.

Source: Netlify docs: custom headers

X-Content-Type-Options

Keep X-Content-Type-Options with the value nosniff under the path.

_headers

/*
  X-Content-Type-Options: nosniff

Source: Netlify docs: custom headers

Referrer-Policy

Add Referrer-Policy under the path.

_headers

/*
  Referrer-Policy: strict-origin-when-cross-origin

Source: Netlify docs: custom headers

Permissions-Policy

Add Permissions-Policy under the path.

_headers

/*
  Permissions-Policy: camera=(), microphone=(), geolocation=()

Each feature with an empty list () is switched off for every origin. Name the features the site does not use.

Source: Netlify docs: custom headers

How to check it

After the next deploy, read the headers the live site sends with curl -I https://www.example.com/ or in the network panel of your browser developer tools. The free check gives an A to F grade and shows how to fix the first two findings in a few seconds, with no sign-up. Run the free check.

More on each header: how to fix a missing HSTS header, how to fix a missing Content-Security-Policy header, how to fix a missing X-Frame-Options header and the security headers guide.

The same headers on other platforms: Vercel, WordPress and Webflow.