1 min read

The CSP nonce that bit back

A field report on strict CSP with htmx: what broke, what the spec actually says, and the one line that fixes it.

  • Security
  • htmx

Strict CSP with unsafe-inline removed is the right default, and htmx
cooperates better than most frameworks. But three details will bite:

  1. htmx injects indicator styles at runtime. A <style> tag from JS is
    inline CSS, which style-src 'self' blocks. Disable it:
    <meta name="htmx-config" content='{"includeIndicatorStyles":false}'>
    and ship the styles yourself.

  2. Nonces must rotate per request or they're as useless as hashes.
    Middleware: generate 16 random bytes, base64, put it in both the CSP
    header and the templ render context.

  3. strict-dynamic is load-bearing. It lets your nonced bootstrap
    script load its own modules while the page stays closed to injected
    scripts. Without it, every dynamic import becomes a CSP violation.

The win: zero inline handlers, zero allowlisted domains, and a policy you
can actually reason about.