CSP & Security Headers
Content Security Policy configuration, security headers, and troubleshooting CSP violations on Arcturus-Prime
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
| Header | Value | Purpose |
|---|---|---|
| X-Content-Type-Options | nosniff | Prevents MIME-type sniffing |
| X-Frame-Options | SAMEORIGIN | Allows same-origin iframes (needed for F12 Console Audit) |
| X-XSS-Protection | 1; mode=block | Legacy XSS filter (browser support varies) |
| Referrer-Policy | strict-origin-when-cross-origin | Full referrer to same origin, origin-only to cross-origin |
| Permissions-Policy | camera=(), microphone=(self), geolocation=() | Disables camera/geo, allows mic (voice features) |
| Cross-Origin-Opener-Policy | same-origin | Isolates browsing context |
| Cross-Origin-Resource-Policy | same-origin | Restricts resource loading to same origin |
| HSTS | max-age=31536000; includeSubDomains; preload | Forces 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
| Directive | Allowed Sources | What It Controls |
|---|---|---|
default-src | 'self' | Fallback for unlisted resource types |
script-src | 'self' 'unsafe-inline' data: static.cloudflareinsights.com cdn.jsdelivr.net | JavaScript execution |
style-src | 'self' 'unsafe-inline' cdnjs.cloudflare.com fonts.googleapis.com | CSS loading |
font-src | 'self' cdnjs.cloudflare.com fonts.gstatic.com | Font 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.com | XHR, fetch, WebSocket |
frame-src | 'self' *.Arcturus-Prime.com Arcturus-Prime.cloudflareaccess.com | Iframe 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 Type | Directive | Example |
|---|---|---|
| External JS library | script-src | cdn.jsdelivr.net |
| External CSS/fonts | style-src + font-src | fonts.googleapis.com + fonts.gstatic.com |
| API calls (fetch/XHR) | connect-src | api.github.com |
| Embedded iframes | frame-src | *.Arcturus-Prime.com |
| Images from CDN | img-src | Already 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
- Identify the blocked resource from the console error message
- Determine the directive — the error message names it explicitly
- Add the domain to the relevant directive in
public/_headersline 178 - Commit and push — CF Pages applies the new headers on next deploy
- Verify with a hard refresh (Ctrl+Shift+R) to bypass cache
Common Gotchas
- Cache delay —
public/_headershas a 5-minute cache for admin pages. Wait or hard-refresh. - Wildcard subdomain —
*.Arcturus-Prime.comcovers subdomains but NOTArcturus-Prime.comitself (both must be listed inconnect-src). blob:for img-src — dynamically generated images (canvas exports, PDF previews) useblob:URLs that need explicit allowlisting.- WebSocket —
wss://*.Arcturus-Prime.cominconnect-srccovers 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.
Related
- F12 Console Audit — automated console error detection using iframes
- Cloudflare Pages — deployment and hosting configuration