Skip to content

Feature/improve csp - #246

Open
blopker wants to merge 6 commits into
mainfrom
feature/improve-csp
Open

Feature/improve csp#246
blopker wants to merge 6 commits into
mainfrom
feature/improve-csp

Conversation

@blopker

@blopker blopker commented Jul 17, 2026

Copy link
Copy Markdown
Member

No description provided.

blopker added 6 commits July 16, 2026 17:26
GA4/gtag was only sending default pageviews (PostHog covers those), and
its ad-network pings were the bulk of the CSP report noise. The CSP now
covers what the reports showed we actually load: the Flutter room app's
upstream host and blob:/wasm/gstatic needs, LiveKit Cloud signaling
(including regional endpoints), both first-party CDN hosts, and the
YouTube/NPR embeds in site content.
script-src now uses nonces instead of unsafe-inline, so injected inline
scripts get blocked once the policy is enforced. External scripts are
unaffected (host allowlist still applies), which keeps the Cloudflare
edge-injected beacon working.

The two views that serve HTML we don't render — the Webflow marketing
pages and the Flutter room app at /room/ — can't carry nonces, so they
swap in their own policies via csp_override_from_settings, which follows
whichever mode (report-only/enforce) is configured. This also scopes the
room app's wasm-unsafe-eval, gstatic, blob:, and LiveKit grants to
/room/ instead of the whole site.

Inline onclick= handlers (blocked by CSP even with nonces) are replaced
by delegated data-copy / data-show-modal / data-dismiss-alert actions.
The site policy is ~1KB and mints a nonce per response — dead weight on
API routes, where scripts can't run. JSON responses now get the minimal
locked-down policy (default-src 'none'; frame-ancestors 'none'),
enforced immediately, with no report-only header. Keyed on content type
rather than path so it covers all JSON and spares HTML like /api/docs.
Raster images (OG previews), CSV/plain-text exports, CSS, JS, fonts, and
wasm can't execute scripts even when navigated to directly, so they get
the same 50-byte enforced policy as JSON instead of the ~1KB site policy
with an unused nonce. Deliberately a deny-list of provably inert types:
SVG, XML, XHTML, and PDF render as scriptable documents and keep the
site policy.
Correctness:
- Convert the three remaining inline event handlers that nonces can't
  cover: the onboard referral Select's onchange (now wired in its nonced
  script), the admin dropdown filter's onChange (same), and the Image
  admin's copy-to-clipboard onclick (now data-copy + a small admin JS
  file loaded via ModelAdmin.Media).
- Allow the Sentry ingest hosts in the room policy's connect-src — the
  Flutter room app reports browser-side crashes to Sentry, which
  enforcement would have silently blocked.
- Delete stale global.d.ts declarations for the removed dismiss_alert /
  copyTextToClipboard globals.
- Make csp_override_from_settings fail fast on a typo'd setting name
  instead of silently dropping the override.

Cleanup:
- Build CSP_ROOM_OVERRIDE on _CSP_BASE (explicit frame-src 'self') so
  hardening/report-uri changes propagate to /room/.
- Drop the dead init guard in clickActions.
- Share the fake_upstream test helper via conftest; drop unneeded db
  fixtures from three CSP tests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant