Skip to content

:head is unusable on a generated page: the CSP nonce is never substituted #19

Description

@borkdude

What happens

On a page without :index, anything style- or script-shaped passed as :head is silently refused by the CSP. The page renders unstyled and the browser logs a CSP violation, with nothing pointing back at :head as the cause.

Why

csp sets style-src 'nonce-<nonce>' — no 'self', no 'unsafe-inline'. So a <style> block, an inline <script>, or a <link rel="stylesheet"> is admitted only when it carries that nonce.

The nonce is reachable from :index but not from :head:

  • rendered-page ends with (str/replace html "NONCE" nonce), so an index file writes nonce="NONCE" and gets the real value.
  • generated-page concatenates head verbatim. There is no substitution, and the nonce is not exposed to the caller in any other way.

The result is that :head cannot carry styles or inline scripts at all on a generated page. An external script still works, since script-src includes 'self', which makes the failure look inconsistent: your <script src=...> runs, your <style> does not.

Related, and probably worth a line of docs either way: rendered-page destructures only :index and :mounts, so :head is ignored outright once :index is set.

Repro

(buzz/handler {:mounts [{:el \"app\" :ui #'my-app}]
               :head   \"<style>body { background: #111; color: #eee }</style>\"})

The page renders with default styling. Console shows the style block refused by CSP.

Suggested fix

Substitute in head the same way rendered-page does for the whole document, so :head can use the literal NONCE:

(str/replace (or head \"\") \"NONCE\" nonce)

That keeps one convention for both page paths. An alternative, if :head should stay literal, is to accept a function of the nonce.

Workaround

Switch to :index and put the styles in the file with nonce=\"NONCE\", as public/index.html already does. That works, but it costs you the generated page: the mount elements now have to be listed by hand in the HTML, which drifts as soon as a mount is added.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions