Skip to main content
Site Architecture

CSP & Security Headers

Content Security Policy configuration, security headers, and troubleshooting CSP violations on Arcturus-Prime

March 1, 2026

CSP & Security Headers

Arcturus-Prime serves security headers via public/_headers, which Cloudflare Pages applies to all responses. The most complex of these is the Content-Security-Policy (CSP) header, which controls what resources the browser is allowed to load.

Header File

All security headers are defined in public/_headers under the /* catch-all rule. Cloudflare Pages reads this file at deploy time and applies the headers to matching routes.

Active Security Headers

HeaderValuePurpose
X-Content-Type-OptionsnosniffPrevents MIME-type sniffing
X-Frame-OptionsSAMEORIGINAllows same-origin iframes (needed for F12 Console Audit)
X-XSS-Protection1; mode=blockLegacy XSS filter (browser support varies)
Referrer-Policystrict-origin-when-cross-originFull referrer to same origin, origin-only to cross-origin
Permissions-Policycamera=(), microphone=(self), geolocation=()Disables camera/geo, allows mic (voice features)
Cross-Origin-Opener-Policysame-originIsolates browsing context
Cross-Origin-Resource-Policysame-originRestricts resource loading to same origin
HSTSmax-age=31536000; includeSubDomains; preloadForces HTTPS for 1 year

Content Security Policy

The CSP header is a single line in public/_headers (line 178). Each directive controls a different resource type.

Current Directives

DirectiveAllowed SourcesWhat It Controls
default-src'self'Fallback for unlisted resource types
script-src'self' 'unsafe-inline' data: static.cloudflareinsights.com cdn.jsdelivr.netJavaScript execution
style-src'self' 'unsafe-inline' cdnjs.cloudflare.com fonts.googleapis.comCSS loading
font-src'self' cdnjs.cloudflare.com fonts.gstatic.comFont file loading
img-src'self' data: blob: https:Image loading (permissive — allows any HTTPS)
connect-src'self' *.Arcturus-Prime.com Arcturus-Prime.com wss://*.Arcturus-Prime.com static.cloudflareinsights.com Arcturus-Prime.cloudflareaccess.com api.github.comXHR, fetch, WebSocket
frame-src'self' *.Arcturus-Prime.com Arcturus-Prime.cloudflareaccess.comIframe sources
object-src'none'Blocks Flash/Java applets
base-uri'self'Prevents <base> tag hijacking

Why unsafe-inline Is Required

Arcturus-Prime uses Astro’s <script is:inline> pattern extensively for pages that need DOM manipulation with View Transitions compatibility. These emit literal inline <script> blocks in the HTML. Without 'unsafe-inline', all inline scripts and styles would be blocked.

A nonce-based approach would be more secure but requires SSR middleware to inject a unique nonce per request into both the CSP header and every <script>/<style> tag — significant complexity for a site behind Cloudflare Access authentication.

Adding New Third-Party Resources

When integrating a new external service, determine which CSP directives need updating:

Resource TypeDirectiveExample
External JS libraryscript-srccdn.jsdelivr.net
External CSS/fontsstyle-src + font-srcfonts.googleapis.com + fonts.gstatic.com
API calls (fetch/XHR)connect-srcapi.github.com
Embedded iframesframe-src*.Arcturus-Prime.com
Images from CDNimg-srcAlready allows https: broadly

Google Fonts requires TWO directives: fonts.googleapis.com in style-src (serves the CSS file) and fonts.gstatic.com in font-src (serves the actual WOFF2 font files).

Troubleshooting CSP Violations

CSP violations appear in the browser console as:

Refused to load the stylesheet 'https://fonts.googleapis.com/...'
because it violates the following Content Security Policy directive:
"style-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com".

Steps to Fix

  1. Identify the blocked resource from the console error message
  2. Determine the directive — the error message names it explicitly
  3. Add the domain to the relevant directive in public/_headers line 178
  4. Commit and push — CF Pages applies the new headers on next deploy
  5. Verify with a hard refresh (Ctrl+Shift+R) to bypass cache

Common Gotchas

  • Cache delaypublic/_headers has a 5-minute cache for admin pages. Wait or hard-refresh.
  • Wildcard subdomain*.Arcturus-Prime.com covers subdomains but NOT Arcturus-Prime.com itself (both must be listed in connect-src).
  • blob: for img-src — dynamically generated images (canvas exports, PDF previews) use blob: URLs that need explicit allowlisting.
  • WebSocketwss://*.Arcturus-Prime.com in connect-src covers secure WebSocket connections to Arcturus-Prime subdomains.

X-Frame-Options: SAMEORIGIN

This header was changed from DENY to SAMEORIGIN to support the F12 Console Audit feature, which loads every page in a hidden same-origin iframe to capture console errors. The SAMEORIGIN value still prevents external sites from embedding Arcturus-Prime pages.

securitycspheaderscloudflare