Security

Security headers

The header set and Content Security Policy applied to every response.

kreogen uses Nosecone to set security-related response headers. It runs in middleware, so every response carries them — including redirects.

// apps/app/proxy.ts
import { noseconeOptions, securityMiddleware } from '@kreogen/security/proxy';

const securityHeaders = securityMiddleware(noseconeOptions);

Defaults cover Strict-Transport-Security, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Cross-Origin-* and friends. See the Nosecone reference for the full list.

Content Security Policy

Unlike the upstream template this is derived from, CSP is enabled. A policy that ships disabled is a policy nobody ever turns on.

It is defined in packages/security/proxy.ts, grouped by the integration that needs each origin — so removing an integration means deleting its group rather than picking entries out of one long list:

const POSTHOG = [
  'https://us.i.posthog.com',
  'https://us-assets.i.posthog.com',
] as const;

const STRIPE = ['https://js.stripe.com', 'https://api.stripe.com'] as const;

The as const is required. Nosecone types sources as a template-literal union, so a plain string[] will not typecheck.

The policy is report-only in development, so a missing directive shows up as a console warning while you work, and enforced everywhere else.

Adding an origin

When you add an integration that talks to a new host, add it to the relevant directive. Miss this and the request is blocked in production while working fine in development — the most annoying possible failure mode.

The directives most often needing extension:

DirectiveFor
connectSrcAPIs, websockets, analytics ingestion
scriptSrcThird-party scripts
imgSrcRemote images, avatars, CDNs
frameSrcEmbedded checkout, video, iframes

Notes on the defaults

'unsafe-inline' is present in scriptSrc because Next inlines its bootstrap and hydration payload. The stricter alternative — per-request nonces with 'strict-dynamic' — requires threading a nonce from middleware through every script tag, and is worth doing for applications handling sensitive data.

frameAncestors is 'none' and objectSrc is 'none'. Loosen the first only if the app is deliberately embeddable.

upgradeInsecureRequests is on outside development.

Verifying

Check what is actually being sent:

curl -sI https://app.example.com | grep -i "content-security-policy\|strict-transport"

securityheaders.com grades a deployed origin.