The kit ships a solid baseline (HSTS, X-Frame-Options, nosniff, Referrer-Policy) on every route, but no Content-Security-Policy and no Permissions-Policy.
Last reviewed June 13, 2026 by SecureStartKit Team
The short answer
Security headers are a cheap, app-wide layer of defense set once in next.config.ts. The baseline almost every app should send: Strict-Transport-Security, X-Frame-Options (or frame-ancestors), X-Content-Type-Options nosniff, and a sensible Referrer-Policy. The two that take real work and matter most against XSS and feature abuse are Content-Security-Policy and Permissions-Policy. Headers are defense in depth, not a substitute for escaping output and validating input.
Where it shows up: The app sends no Content-Security-Policy and no Permissions-Policy, or ships with none of the baseline headers configured in next.config.ts.
// next.config.ts (no headers configured)
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
images: { remotePatterns: [{ protocol: 'https', hostname: '*.supabase.co' }] },
// no async headers(): every response ships with browser defaults only
}
export default nextConfigWith no headers() function, responses carry no HSTS, no frame protection, and no nosniff. Every one of those is a one-line default the app is choosing to skip.
// next.config.ts (baseline headers on every route)
const securityHeaders = [
{ key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' },
{ key: 'X-Frame-Options', value: 'DENY' },
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
]
const nextConfig = {
async headers() {
return [{ source: '/(.*)', headers: securityHeaders }]
},
}This is the kit’s actual baseline in next.config.ts. HSTS forces HTTPS, X-Frame-Options: DENY blocks framing, and nosniff stops MIME confusion, applied to every route.
// baseline only: the XSS-containing header and feature lockdown are missing
const securityHeaders = [
{ key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' },
{ key: 'X-Frame-Options', value: 'DENY' },
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
// no Content-Security-Policy
// no Permissions-Policy
]This is the kit today: a solid baseline, but nothing to contain an injected script and nothing to lock down browser features. The two highest-value headers are the two that are missing.
const securityHeaders = [
{ key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' },
{ key: 'X-Frame-Options', value: 'DENY' },
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
{
key: 'Content-Security-Policy',
value: "default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'",
},
{ key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
]The CSP restricts where scripts may load from and disallows inline script, so an injected payload cannot run or phone home. Permissions-Policy denies powerful browser features by default. Roll the CSP out in Content-Security-Policy-Report-Only first, watch the violation reports, then enforce.
Each missing header removes a specific, cheap mitigation, and the costs compound.
No Content-Security-Policy is the expensive one. An injected script, whether from an XSS hole, a compromised third-party script, or an inline event handler, runs with full page privileges and can read tokens and exfiltrate them to any origin. A CSP that disallows inline script and restricts script-src to your own origin would have blocked the injection from running or stopped its outbound call. Without it, an XSS bug escalates straight to data theft with nothing in the way.
No X-Frame-Options or frame-ancestors means your authenticated pages can be loaded in a hidden iframe on an attacker site and used for clickjacking. No X-Content-Type-Options nosniff lets a browser MIME-sniff a response into a script context it was never meant to run in. No Strict-Transport-Security leaves the first request open to an HTTP downgrade or interception before HTTPS is enforced.
The realistic chain is the CSP one: a single reflected or stored XSS, which a content security policy would have contained, becomes full account takeover because the injected script faces no restriction on what it can run or where it can send what it reads.
Check what your deployed app actually sends. A single request shows every response header:
curl -sI https://your-app.com | grep -iE "content-security|x-frame|x-content-type|strict-transport|referrer|permissions-policy"
Anything absent from that list is a header you are not sending. Then open next.config.ts and confirm an async headers() function returns the set you expect for the /(.*) source.
For a scored report that flags missing and weak headers, run the app through a header scanner such as the Mozilla Observatory or securityheaders.com, and treat a missing Content-Security-Policy as the priority finding.
Myth“Next.js or my host adds a Content-Security-Policy for me.”
It does not. Next.js sends no CSP by default, and a platform default, if any, will not match your app. You have to define and tune the policy yourself.
Myth“My site is HTTPS, so I do not need these headers.”
HTTPS encrypts transport. HSTS, CSP, and frame-ancestors solve different problems: downgrade attacks, script injection, and clickjacking. Transport encryption does not address any of those.
Myth“A CSP breaks my app, so I will skip it.”
Start in report-only mode, which enforces nothing while reporting what would have been blocked, then tighten until clean and switch to enforcing. Skipping it entirely leaves every XSS uncontained.
Myth“X-XSS-Protection handles XSS for me.”
That header is deprecated and ignored by modern browsers, and could introduce its own issues. Content-Security-Policy is its replacement and the actual mitigation.
SecureStartKit already sends a real baseline from `next.config.ts` on every route: `Strict-Transport-Security` with preload, `X-Frame-Options: DENY`, `X-Content-Type-Options: nosniff`, `Referrer-Policy: strict-origin-when-cross-origin`, and `X-DNS-Prefetch-Control`. That closes clickjacking and MIME-sniffing out of the box. What it does not ship is a `Content-Security-Policy` or a `Permissions-Policy`, which are the two that take tuning and that would contain an XSS payload and lock down browser features. Add both, rolling the CSP out in report-only first, and you have the full set rather than the baseline.
Next.js security headers generator