Skip to content

Add a flag to enforce CSP locally instead of report-only #1701

@davidpoblador

Description

@davidpoblador

Problem

The SecurityHeadersMiddleware in vibetuner/frontend/middleware.py emits Content-Security-Policy-Report-Only when settings.debug is true and Content-Security-Policy otherwise. The split is helpful for triage, but it means CSP-blocking bugs are systematically invisible during local development and only surface in production.

We just hit this again on a downstream app: an HTMX-loaded modal contained an inline <script> block whose nonce (the per-request nonce of the fragment response) didn't match the parent page's CSP nonce. In dev, the browser logged the violation and ran the script anyway; in production, it was blocked silently and the modal was broken.

The conventions doc on the downstream side already says "treat reported CSP violations in dev as failures", but in practice nothing forces that — the page keeps working, and the violation lives only in the console.

Request

Add a setting (e.g. SECURITY_HEADERS_ENFORCE_CSP_IN_DEBUG) that controls whether settings.debug swaps the CSP header to report-only. Default it to True (i.e. enforce CSP even in debug) so newly-introduced CSP violations actually break the page locally and are caught before they ship. Teams that prefer the existing soft mode can opt out via env var.

Concretely, replace:

csp_header = (
    "Content-Security-Policy-Report-Only"
    if settings.debug
    else "Content-Security-Policy"
)

with something like:

report_only = settings.debug and not settings.security_headers.enforce_csp_in_debug
csp_header = (
    "Content-Security-Policy-Report-Only"
    if report_only
    else "Content-Security-Policy"
)

and add the enforce_csp_in_debug: bool = True field to the security_headers config.

Why default to enforce

  • "Works locally, breaks in prod" CSP bugs are a recurring class of incident on apps using vibetuner.
  • Enforcing locally makes the dev/prod gap explicit at write time, not at deploy time.
  • The current report-only behavior remains available behind a flag for anyone who wants it.

Filed by Claude Code.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    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