From 24d0c1b9bdc9dec6c888ccdbb879ee10c655e2ab Mon Sep 17 00:00:00 2001 From: propcgamer20-png Date: Tue, 8 Sep 2026 17:35:00 +0000 Subject: [PATCH] chore: add security headers to next.config.js Adds X-Content-Type-Options, Referrer-Policy, Permissions-Policy, and X-Frame-Options across all routes. geolocation stays enabled for this origin (the 'Near me' feature genuinely uses it); camera/microphone are disabled since nothing here uses them. A full CSP is a bigger, separate effort (MapTiler, Supabase, Vercel Analytics, Leaflet/OG pipelines) and is left for a follow-up, as the issue itself scopes it. Note on verification: couldn't run 'npm run build' + curl -I in this environment - the build fails on fetching Google Fonts regardless of this change (confirmed identically on unmodified main, unrelated network restriction in this sandbox). Verified the headers() function directly instead (node -e requiring next.config.js and awaiting headers()) - returns exactly the four rules above. Worth a real curl -I check against a local next start before merging. Fixes #254 --- next.config.js | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/next.config.js b/next.config.js index 658404a..1feb798 100644 --- a/next.config.js +++ b/next.config.js @@ -1,4 +1,29 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const nextConfig = { + // Basic hardening headers on every route. A full Content-Security-Policy + // is a bigger, separate effort (it would need to account for MapTiler + // tiles, Supabase, Vercel Analytics, and the Leaflet/OG image pipelines) + // and is left for a follow-up. + async headers() { + return [ + { + source: "/:path*", + headers: [ + { key: "X-Content-Type-Options", value: "nosniff" }, + { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" }, + // geolocation stays enabled for this origin - the "Near me" + // feature genuinely uses it. Everything else this app doesn't + // use is disabled. + { + key: "Permissions-Policy", + value: "camera=(), microphone=(), geolocation=(self)", + }, + // Nothing in the app needs to be iframed. + { key: "X-Frame-Options", value: "DENY" }, + ], + }, + ]; + }, +}; module.exports = nextConfig;