Home / Guides

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.

Updated 2026-10-15 · ShipCheck guides

Security headers are instructions your server sends with every response. They tell the browser to refuse dangerous behaviour: running injected scripts, being framed by another site, downgrading to HTTP, or guessing file types. On Vercel you add them with a few lines in vercel.json, with no code changes and no extra cost.

The copy-paste vercel.json

Put this in the root of your project next to package.json. If you already have a vercel.json, merge the headers array into it.

{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        { "key": "Strict-Transport-Security", "value": "max-age=63072000; includeSubDomains; preload" },
        { "key": "X-Content-Type-Options", "value": "nosniff" },
        { "key": "X-Frame-Options", "value": "DENY" },
        { "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" },
        { "key": "Permissions-Policy", "value": "camera=(), microphone=(), geolocation=()" },
        { "key": "Content-Security-Policy", "value": "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'" }
      ]
    }
  ]
}

"source": "/(.*)" applies the headers to every path. Commit, push, and Vercel applies them on the next deployment.

What each header does

Adapting the CSP to a real app

The strict policy above suits a site that serves everything from its own domain. Most vibe-coded apps call other services, so you will need to add their origins:

Frameworks such as Next.js and Vite inject inline scripts for hydration. If those break, the quick fix is 'unsafe-inline' in script-src, which weakens protection against XSS. The better fix in Next.js is a nonce-based CSP set in middleware. See the Next.js docs on Content Security Policy.

Roll out CSP safely with Report-Only

To avoid breaking production, first ship the policy under the key Content-Security-Policy-Report-Only. The browser then logs violations in the console without blocking anything. Click through the app (sign-in, checkout, uploads), fix anything it reports, then rename the key to Content-Security-Policy.

Headers for specific paths

Rules are evaluated in order, and a later matching rule can override a header. For example, to allow one embeddable widget page to be framed:

{ "source": "/embed/(.*)", "headers": [
  { "key": "X-Frame-Options", "value": "SAMEORIGIN" },
  { "key": "Content-Security-Policy", "value": "frame-ancestors https://partner.com" }
]}

Next.js alternative

In Next.js you can set the same headers in next.config.js with async headers() { return [{ source: '/(.*)', headers: [...] }] }. Pick one place, either that or vercel.json, not both.

Test that they are live

curl -sI https://yourapp.com | grep -iE "strict-transport|content-security|x-frame|x-content-type|referrer-policy|permissions-policy"

Or run a free ShipCheck scan. It checks HTTPS and each of these headers, flags weak CSPs, and gives you a fix for anything missing. Using Netlify instead? See security headers on Netlify.

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

Does Vercel add security headers by default?

Vercel serves every deployment over HTTPS and sends HSTS on its own vercel.app domains. Your custom domain still needs CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy and Permissions-Policy. Add them yourself in vercel.json or your framework config.

Should I use vercel.json or next.config.js for headers?

Either works for Next.js. vercel.json works for any framework, including static sites and Vite apps. Do not define the same header in both places, or you will have trouble working out which value wins.

Why did my site break after adding a Content-Security-Policy?

The CSP is blocking a script, style, font, image or API your site needs. Open the browser console to see which URL was blocked, add that origin to the right directive, or start with Content-Security-Policy-Report-Only while you tune it.

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 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.

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.