Uh oh!
There was an error while loading. Please reload this page.
www: ship security response headers - #34
Conversation
No CSP, HSTS, nosniff, Referrer-Policy or frame-ancestors on the marketing site. Low stakes — a static page with no auth, no cookies and no user input, so there is no session to steal and no injection sink — but frame-ancestors 'none' is free clickjacking cover and the rest is a clean scanner report. Set in two places, which is duplication but not redundancy. Under OpenNext the document is rendered by the Worker while /_next/static/* and public/ are served straight off the Cloudflare assets binding, so next.config's headers() covers the first and public/_headers the second — and neither covers the other: route _headers only next.config only / none all five /favicon.svg all five none Measured against `opennextjs-cloudflare preview`, not assumed; the issue's suggested _headers-only approach would have left the actual page uncovered. script-src keeps 'unsafe-inline' because Next inlines the hydration payload (12 <script> blocks of self.__next_f.push in the rendered document); hashes churn per build and nonces would deopt static rendering. HSTS is without preload, deliberately. Closes#22
z33b0t
commented
Jul 29, 2026
@z33b0t ready to merge. All 6 checks green (CodeQL across all five languages). Note the site build did not run on this PR — Suggested order: merge #38 first, then this. That gets the site build running on PRs, and if you push a rebase here the headers change would get a real CI build before it deploys — which is precisely the hazard #16 describes, applied to this PR. Two things flagged in the PR body worth a decision:
|
z33b0t
commented
Jul 29, 2026
@z33b0t Green, and I'm holding this one deliberately rather than merging. You asked for dependency order, and this sits behind #38 — which adds the Why it matters for this PR specifically: merging it now pushes a CSP straight to production having never been built by CI, and I couldn't do a browser render check either. Local Once #38 lands, push any commit here (or I will) so the site build runs on this PR, then it's safe to merge. |
Uh oh!
There was an error while loading. Please reload this page.
Adds CSP, HSTS,
nosniff,Referrer-PolicyandX-Frame-Optionsto the marketing site.The issue's open question, answered
It's both, and neither substitutes for the other. Measured against
opennextjs-cloudflare preview(local workerd), counting how many of the five headers came back:_headersonlynext.configonly/(Worker-rendered document)/favicon.svg(assets binding)Under OpenNext the document is rendered by the Worker, while
/_next/static/*andpublic/are served straight off the Cloudflare assets binding without the Worker running. So the_headers-only approach the issue sketches would have left the page — the one thingframe-ancestorsprotects — completely uncovered. Hence both, with a comment in each file pointing at the other.On
unsafe-inline<script>blocks (self.__next_f.push(...), Next's hydration payload). Hashes churn every build; nonces need middleware and would opt the page out of static rendering.<style>elements and zerostyle=attributes, and there are nostyle={{…}}props anywhere inwww/src. Sostyle-src 'self'would very likely work today. I left'unsafe-inline'in because I couldn't do a real browser render check (no browser tooling in this session) and a wrong guess breaks the site's front page silently. Happy to tighten it if you'll eyeball the preview.Verification
curl -D -)..woff2under/_next/static/. Nodata:URIs, no inline event handlers. The only absolute URLs are four anchorhrefs (github.com, lightware.dev), which are navigations and unaffected by this policy.Closes#22