Background
Surfaced during the security review of #519 / #523. Not a regression from that PR — a pre-existing, defense-in-depth gap.
Observation
The site sets no security response headers anywhere — no Content-Security-Policy, X-Content-Type-Options, X-Frame-Options / frame-ancestors, or HSTS. Perl.com is a static Hugo build with no runtime, so the practical XSS surface today is limited to build-time template output, and Go's html/template contextual autoescaping is intact (the #523 review confirmed no safeHTML/safeURL bypasses). A CSP would be the backstop if that single line of defense ever slipped.
Suggested fix
Configure at the hosting / CDN layer (this is TPF-managed staging, not something in this repo's build):
Content-Security-Policy: default-src 'self'; object-src 'none'; frame-ancestors 'self' (tune for Google Analytics / any external assets currently loaded)
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
X-Frame-Options: SAMEORIGIN (or rely on frame-ancestors)
Scope / notes
- Hosting-layer change, not a code change — needs coordination with whoever controls the perl.com CDN/staging config. Note current inline
<script> for Google Analytics in header.html, which affects how strict the CSP can be without nonces/hashes.
- Low urgency given the static-only surface, but a cheap hardening once the header mechanism is available.
Filed from the multi-reviewer pass on #523.
Background
Surfaced during the security review of #519 / #523. Not a regression from that PR — a pre-existing, defense-in-depth gap.
Observation
The site sets no security response headers anywhere — no
Content-Security-Policy,X-Content-Type-Options,X-Frame-Options/frame-ancestors, or HSTS. Perl.com is a static Hugo build with no runtime, so the practical XSS surface today is limited to build-time template output, and Go'shtml/templatecontextual autoescaping is intact (the #523 review confirmed nosafeHTML/safeURLbypasses). A CSP would be the backstop if that single line of defense ever slipped.Suggested fix
Configure at the hosting / CDN layer (this is TPF-managed staging, not something in this repo's build):
Content-Security-Policy: default-src 'self'; object-src 'none'; frame-ancestors 'self'(tune for Google Analytics / any external assets currently loaded)X-Content-Type-Options: nosniffStrict-Transport-Security: max-age=63072000; includeSubDomains; preloadX-Frame-Options: SAMEORIGIN(or rely onframe-ancestors)Scope / notes
<script>for Google Analytics inheader.html, which affects how strict the CSP can be without nonces/hashes.Filed from the multi-reviewer pass on #523.