From 2e52bffac2c9c81f3405fac8637b3217b3a356f2 Mon Sep 17 00:00:00 2001 From: Jeff <138259519+jdotc1@users.noreply.github.com> Date: Mon, 9 Nov 2026 00:04:17 -0500 Subject: [PATCH 1/2] fix(security): add configurable response hardening headers --- frontend/next.config.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frontend/next.config.js b/frontend/next.config.js index 5ac3210..47f24b0 100644 --- a/frontend/next.config.js +++ b/frontend/next.config.js @@ -1,4 +1,5 @@ const isDev = process.env.NODE_ENV !== "production"; +const hstsEnabled = !isDev && process.env.PRISM_ENABLE_HSTS === "true"; /** Origins of the configured Horizon and RPC endpoints, skipping any value that isn't a URL. */ function endpointOrigins() { @@ -40,6 +41,11 @@ const nextConfig = { { key: "Content-Security-Policy", value: contentSecurityPolicy }, { key: "X-Frame-Options", value: "DENY" }, { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" }, + { key: "X-Content-Type-Options", value: "nosniff" }, + { key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=(), payment=(), usb=()" }, + ...(hstsEnabled + ? [{ key: "Strict-Transport-Security", value: "max-age=31536000" }] + : []), ], }, ]; From 753e032adeb8b524298aa8a315d0a42919f32703 Mon Sep 17 00:00:00 2001 From: Jeff <138259519+jdotc1@users.noreply.github.com> Date: Mon, 9 Nov 2026 00:04:27 -0500 Subject: [PATCH 2/2] docs: explain frontend security headers and HSTS opt-in --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index 4a0f3a4..84b6ed8 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,22 @@ This runs Postgres, the indexer (`indexer/`), and the frontend together — see The Postgres port is published only on `127.0.0.1`. Compose uses `prism` as a local-development-only default for `POSTGRES_PASSWORD`; set a strong value in your environment before starting the stack if you need a different password. Do not use the default for a production deployment. +### Security headers + +The frontend sends a Content Security Policy, `X-Frame-Options: DENY`, +`Referrer-Policy: strict-origin-when-cross-origin`, +`X-Content-Type-Options: nosniff`, and a restrictive `Permissions-Policy` on +all paths. The permissions policy disables camera, microphone, geolocation, +payment, and USB browser features, which Prism does not use. + +For an HTTPS-only production deployment, opt in to HTTP Strict Transport +Security by setting `PRISM_ENABLE_HSTS=true` **when building the frontend** +(for example, `PRISM_ENABLE_HSTS=true npm run build`). The production response +then includes `Strict-Transport-Security: max-age=31536000`. HSTS is absent in +development and when the variable is unset, so local HTTP remains usable. +Only enable HSTS after confirming that the public hostname is served over +HTTPS; browsers can remember the policy for up to a year. + ### Rate limits and reverse proxies Every `/api/*` route is rate-limited per client: 30 requests per minute, except `/api/contract/[id]/simulate` at 10 per minute. Each route keeps its own counter, so hitting the limit on one route doesn't block the others. Over the limit, the API returns `429` with a `Retry-After` header (in seconds).