Skip to content

Inline style attributes can be silently dropped by the CSP nonce in packaged builds #23

Description

@nprudhomme

Context

Found while investigating a report of the whole window becoming unresponsive (no clicks, no scrolling, no file selection) — fixed separately by making transparent overlays click-through. This issue tracks the underlying robustness problem that surfaced during that analysis.

The problem

Tauri injects a nonce on every <style> tag at build time and adds 'nonce-<n>' to the style-src directive. CSP Level 3 mandates that 'unsafe-inline' is ignored as soon as a nonce or hash is present in the directive. Since style-src-attr is not declared separately, it falls back to style-src — and a nonce cannot attach to an attribute.

The consequence: in a packaged build, style="..." attributes can be rejected at parse time, while the <style> block (which carries the nonce) still applies. Mutating styles through the CSSOM from JS (el.style.display = "flex") is unaffected — only the parsed attribute is dropped.

Our CSP (src-tauri/tauri.conf.json):

style-src 'self' 'unsafe-inline'

This does not reproduce on macOS 26.6.1, where inline attributes still apply. Enforcement appears to depend on the WebKit version, which makes this a latent, environment-dependent failure rather than a guaranteed one.

It only ever affects packaged builds: set_csp runs on the embedded-asset path, so npm run tauri dev (served from localhost) never goes through it. Anything broken this way is invisible in development.

Why it matters

index.html carries 9 style= attributes, and several of them are load-bearing rather than cosmetic — they hide elements:

  • #confirm-backdrop — display:none;z-index:2100
  • #prefs-backdrop — display:none
  • #markdown — display:none
  • #prefs-import-error — display:none
  • .prefs-editor-hide — display: contents

If those attributes are dropped, the two backdrops are displayed from the first launch: full-screen, fully transparent, covering the window. That is exactly the shape of the unresponsive-window report, reachable with no user interaction at all.

Proposed fix

  1. Structural (preferred) — stop expressing behaviour through style= attributes. Move display and z-index into classes, e.g. .prefs-backdrop { display: none } .prefs-backdrop.open { display: flex }. Any future CSP hardening then becomes harmless.
  2. Targeted — add style-src-attr 'unsafe-inline' to the CSP. Restores inline attributes while keeping nonce protection on <style> elements via style-src-elem.

The CSS safety net already shipped (.prefs-backdrop:not(.visible) { pointer-events: none; visibility: hidden }) means a stuck backdrop can no longer lock the window, so this is not urgent — but it does not address the cause, and other inline attributes remain exposed.

How to confirm

In a packaged build, open the inspector:

document.querySelector('meta[http-equiv="Content-Security-Policy"]').content
// expect a 'nonce-…' inside style-src

const e = document.getElementById('confirm-backdrop');
[e.getAttribute('style'), e.style.zIndex]
// attribute present but an empty CSSOM value is the signature of CSP blocking

The WebKit console should also log a CSP refusal for the attribute.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions