diff --git a/apps/nextjs/next.config.ts b/apps/nextjs/next.config.ts index d88dac644..e41d0661e 100644 --- a/apps/nextjs/next.config.ts +++ b/apps/nextjs/next.config.ts @@ -49,6 +49,32 @@ const nextConfig: NextConfig = { images: { domains: ["cdn.jsdelivr.net"], }, + // eslint-disable-next-line @typescript-eslint/require-await,no-restricted-syntax + async headers() { + return [ + { + source: "/(.*)", // Apply CSP to all routes + headers: [ + { + key: "Content-Security-Policy", + value: ` + default-src 'self'; + script-src * 'unsafe-inline' 'unsafe-eval'; + base-uri 'self'; + connect-src *; + style-src 'self' 'unsafe-inline'; + frame-ancestors *; + frame-src *; + form-action 'self'; + img-src * data:; + ` + .replace(/\s{2,}/g, " ") + .trim(), + }, + ], + }, + ]; + }, }; // Skip transform is used because of webpack loader, without it for example 'Tooltip.Floating' will not work and show an error diff --git a/packages/validation/src/app.ts b/packages/validation/src/app.ts index 278f4a8b5..c50b17fe0 100644 --- a/packages/validation/src/app.ts +++ b/packages/validation/src/app.ts @@ -4,7 +4,7 @@ export const appHrefSchema = z .string() .trim() .url() - .regex(/^https?:\/\//) // Only allow http and https for security reasons (javascript: is not allowed) + .regex(/^(?!javascript)[a-zA-Z]*:\/\//i) // javascript: is not allowed, i for case insensitive (so Javascript: is also not allowed) .or(z.literal("")) .transform((value) => (value.length === 0 ? null : value)) .nullable();