Security headers
Six security headers applied to every response via proxy.ts.
Where they are set
All security headers are set in proxy.ts on every response using NextResponse.next() with custom headers. This ensures every page, API route, and static file response includes the headers.
proxy.ts
export function proxy(request: NextRequest) {
const response = NextResponse.next()
response.headers.set('X-Frame-Options', 'DENY')
response.headers.set('X-Content-Type-Options', 'nosniff')
response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin')
response.headers.set(
'Permissions-Policy',
'camera=(), microphone=(), geolocation=()'
)
response.headers.set(
'Content-Security-Policy',
"default-src 'self'; script-src 'self' 'unsafe-inline'; " +
"style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; " +
"font-src 'self' data:"
)
if (process.env.NODE_ENV === 'production') {
response.headers.set(
'Strict-Transport-Security',
'max-age=31536000; includeSubDomains'
)
}
return response
}Full header list
| Header | Value | Purpose |
|---|---|---|
| X-Frame-Options | DENY | Prevents clickjacking - disallows the page being embedded in iframes |
| X-Content-Type-Options | nosniff | Prevents MIME type sniffing - browser uses declared content-type only |
| Referrer-Policy | strict-origin-when-cross-origin | Limits referrer info sent to third-party sites |
| Permissions-Policy | camera=(), microphone=(), geolocation=() | Disables sensitive browser APIs |
| Content-Security-Policy | see below | Restricts what resources the page can load |
| Strict-Transport-Security | max-age=31536000; includeSubDomains | Forces HTTPS for 1 year (production only) |
Content-Security-Policy
The CSP header tells the browser which sources are allowed for each resource type. The NextForge default:
- default-src 'self' - all resource types default to same-origin only
- script-src 'self' 'unsafe-inline' - inline scripts allowed (needed for Next.js)
- style-src 'self' 'unsafe-inline' - inline styles allowed (needed for Tailwind)
- img-src 'self' data: https: - images from same origin, data URIs, and any HTTPS source
- font-src 'self' data: - fonts from same origin and data URIs
unsafe-inline is required for Next.js's inline scripts and Tailwind's generated styles. For a stricter CSP using nonces, see the Next.js documentation on CSP with nonces.
HSTS
Strict-Transport-Security is only set in production (process.env.NODE_ENV === 'production'). Setting HSTS in development causes browsers to refuse HTTP connections to localhost permanently - which breaks local development.
The max-age=31536000 value sets the policy for 1 year. includeSubDomains extends it to all subdomains.
Customising
Add, remove, or tighten headers in proxy.ts:
proxy.ts
// Remove Permissions-Policy if you need geolocation:
// response.headers.set('Permissions-Policy', 'geolocation=(self)')
// Tighten CSP to disallow all inline scripts (requires nonce implementation):
// response.headers.set(
// 'Content-Security-Policy',
// "default-src 'self'; script-src 'self'; style-src 'self'"
// )