Insecure Headers on Netlify
Netlify serves static sites with excellent performance but does not add application-level security headers by default. Without a _headers file or netlify.toml configuration, your Netlify site lacks Content-Security-Policy, X-Frame-Options, and Strict-Transport-Security.
Scan Your Netlify AppHow It Happens
Netlify serves static files from a global CDN. Security headers must be configured explicitly through either a _headers file in the publish directory or a [[headers]] section in netlify.toml. Neither file is generated by default in most static site generators or frameworks. Developers who build JAMstack sites on Netlify focus on content and functionality. The _headers file is not part of the typical development workflow for Gatsby, Hugo, Astro, or plain React apps. Without a build step that generates this file, the deployed site has no security headers. Netlify's server-side rendering (SSR) and Edge Functions can set headers programmatically, but most Netlify deployments use purely static hosting. The static hosting pipeline has no middleware layer, so headers must come from configuration files.
Impact
Without Content-Security-Policy, Netlify sites are fully exposed to XSS exploitation. If any user input is rendered unsafely, attackers can load scripts from any domain and exfiltrate data without restriction. Missing X-Frame-Options on a Netlify site allows any website to embed it in an iframe. For sites with forms, authentication, or interactive elements, this enables clickjacking attacks. Without Strict-Transport-Security, users who navigate to your Netlify site via an HTTP link are vulnerable during the redirect to HTTPS. Netlify automatically redirects HTTP to HTTPS, but without HSTS the browser does not remember this for future visits.
How to Detect
Run curl -I https://your-site.netlify.app and check the response for security headers. Look for Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Strict-Transport-Security, Referrer-Policy, and Permissions-Policy. Check your project for a _headers file in the publish directory and a [[headers]] section in netlify.toml. If neither exists, no custom headers are being set. Vibe App Scanner checks all response headers on Netlify-hosted sites and provides ready-to-use configuration for the _headers file format specific to Netlify.
How to Fix
Create a _headers file in your site's publish directory (typically public/ or dist/) with security headers applied to all paths. This is the simplest approach for static Netlify sites. Alternatively, add a [[headers]] section to your netlify.toml configuration file. This has the advantage of being version-controlled with your project and applied regardless of the build output directory. For sites using Netlify Edge Functions, set headers in the function response for dynamic routes. This allows per-route header customization and dynamic CSP with nonces. Test headers after deployment. The _headers file syntax is sensitive to formatting issues. Verify headers are applied correctly using curl or browser DevTools.
Code Examples
Netlify _headers file for security
# No _headers file exists
# Netlify serves the site with no security headers# _headers file in the publish directory
/*
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
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:;Frequently Asked Questions
Does Netlify add any security headers by default?
Netlify handles HTTPS and provides DDoS protection at the infrastructure level, but does not add application-level security headers like CSP, X-Frame-Options, or HSTS to your responses. You must configure these through a _headers file or netlify.toml.
Where should I put the _headers file?
The _headers file must be in the publish directory (the directory Netlify serves). For Gatsby this is public/, for Vite it is dist/, for Hugo it is public/. Place it there or configure your build to copy it during the build step.
Can I use both _headers and netlify.toml for headers?
Yes, but netlify.toml headers take precedence over _headers file entries. Using one approach consistently is recommended to avoid confusion about which headers are being applied.
Related Security Resources
Is Your App Vulnerable?
VAS automatically scans for insecure headers and other security issues in Netlify apps. Get actionable results with step-by-step fixes.
Scans from $5, results in minutes.