Skip to content

feat: add security headers to the Static Web App config#295

Open
henrique221 wants to merge 1 commit into
mainfrom
feat/security-headers
Open

feat: add security headers to the Static Web App config#295
henrique221 wants to merge 1 commit into
mainfrom
feat/security-headers

Conversation

@henrique221
Copy link
Copy Markdown
Contributor

What

Adds a globalHeaders block to staticwebapp.config.json (Azure Static Web Apps): an enforced Content-Security-Policy plus the standard hardening headers.

Closes #291.

Headers

  • CSP (enforced): script-src 'self' + a SHA-256 hash of the inline theme script; object-src 'none', base-uri 'self', frame-ancestors 'none', frame-src 'none'. style-src keeps 'unsafe-inline' (Radix/Tailwind inject inline styles) + cdnjs for the Inter font. connect-src/img-src/media-src use https: allowlists (see notes).
  • HSTS (max-age=31536000; includeSubDomains), X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: strict-origin-when-cross-origin, locked-down Permissions-Policy, X-XSS-Protection: 0.

Verification

Built for production and loaded under these exact headers in a real browser:

  • No CSP violations except the expected http://localhost:9999 API call (HTTPS in prod, so a non-issue).
  • Inter font (cdnjs), SVG icons, Tailwind/Radix styles, the React bundle, App Insights, and the inline theme script (hash valid) all load cleanly. Login page renders pixel-perfect, no FOUC.

Notes for reviewers

  • connect-src/img-src/media-src are intentionally https: — the prod API host is env-specific and Aquifer/avatar image hosts vary. All HTTP/mixed content is still blocked. We can tighten connect-src to an explicit allowlist once the prod API host is settled.
  • The script-src hash is tied to the exact inline theme script in index.html. If that script changes, recompute the hash (otherwise dark-mode init is blocked — benign FOUC, not a crash). CI builds on Node 24 reproduce the same hash.
  • No COOP/COEP and no HSTS preload (preload is hard to reverse; COOP can break OAuth popups) — easy to add later if wanted.

Add a globalHeaders block to staticwebapp.config.json with an enforced
Content-Security-Policy plus HSTS, X-Content-Type-Options, X-Frame-Options,
Referrer-Policy, a locked-down Permissions-Policy, and X-XSS-Protection: 0.

The inline dark-mode theme script in index.html is pinned by a SHA-256 hash
so script-src stays 'self'. connect-src/img-src/media-src use https:
allowlists because the API host is environment-specific and Aquifer/avatar
hosts vary; all HTTP/mixed content is still blocked.
@henrique221 henrique221 added enhancement New feature or request web-app labels Jun 5, 2026
@henrique221 henrique221 self-assigned this Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request web-app

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add security headers to the Static Web App config

1 participant