Skip to content

Enable Tauri CSP and isolate HTML artifact iframes#188

Open
yoshibase wants to merge 1 commit into
andrewyng:mainfrom
yoshibase:security/tauri-csp-hardening
Open

Enable Tauri CSP and isolate HTML artifact iframes#188
yoshibase wants to merge 1 commit into
andrewyng:mainfrom
yoshibase:security/tauri-csp-hardening

Conversation

@yoshibase

Copy link
Copy Markdown

Summary

Fixes #99.

The desktop shell has shipped with app.security.csp: null since the initial import. Any XSS
in the webview could load remote script or open arbitrary connections. The HTML artifact
preview made the practical exploit path worse: it used

sandbox="allow-scripts allow-same-origin"

so agent-authored markup in a srcDoc iframe could reach window.parent.__COWORKER_API_TOKEN__
and drive the local sidecar. Parent CSP alone cannot contain a srcDoc iframe — that sandbox
is the real XSS → tools fix.

What changed

Production CSP (object form in tauri.conf.json), shaped for this codebase:

Directive Why
connect-srcipc: http://ipc.localhost Tauri 2 IPC / withGlobalTauri
http://127.0.0.1:* ws://127.0.0.1:* Sidecar port is free_port()127.0.0.1:0 at launch; a fixed port cannot work
style-src 'self' 'unsafe-inline' Widespread React style={{…}}
worker-src 'self' blob: pdfjs worker via ?url
img-src … data: blob: Attachment / artifact data URLs
no unsafe-eval, no remote https: in connect-src Prod stays tight; the updater is a native Rust plugin, not webview connect-src

devCsp (mandatory): without it, Tauri injects the prod CSP into tauri dev too, and Vite
HMR on localhost:1420 dies. Dev allows 'unsafe-eval' and the Vite HMR hosts; production does
not.

Artifact iframe: drop allow-same-origin. Scripts may still run for interactive previews;
the frame gets a unique opaque origin, so it cannot read the parent token / SPA.

Honest scope note: a per-launch API token already gates the sidecar (#28 / #40 lineage). CSP
is defense-in-depth — especially against remote connect/script. 127.0.0.1:* still allows a
compromised page to talk to any loopback port; pinning one port would require dropping
free_port(), which is out of scope here.

Test plan

Hermetic contract tests (CI does not boot a Tauri webview):

$ pytest tests/test_tauri_csp.py -q
3 passed

They pin:

  • production csp is non-null and contains IPC + 127.0.0.1:* WS/HTTP wildcards
  • no unsafe-eval / no remote https: in prod connect-src
  • devCsp is set and allows Vite HMR on :1420
  • the HTML artifact iframe keeps allow-scripts and does not set allow-same-origin
$ npx tsc --noEmit   # exit 0

Manual smoke (please, before merge — CI will not catch webview CSP breakage):

  1. cd surfaces/gui && npm run tauri dev
  2. Boot → health → one WS turn → Settings
  3. Open an HTML artifact preview, a PDF, and an image attachment
  4. Confirm update check still works (native plugin; not webview connect-src)

No new dependencies. Complementary to #170 (SSRF) and #92 (CORS) — those don't touch
tauri.conf security CSP.

The desktop shell has shipped with `app.security.csp: null` since the initial
import (andrewyng#99). Any XSS in the webview could load remote script or open
arbitrary connections — and the HTML artifact preview made that worse: its
iframe used `sandbox="allow-scripts allow-same-origin"`, so agent-authored
markup could reach `window.parent.__COWORKER_API_TOKEN__` and drive the local
sidecar.

Enable a production CSP shaped for this app:

- connect-src allows Tauri IPC (`ipc:`, `http://ipc.localhost`) and the
  dynamically-chosen sidecar port (`http://127.0.0.1:*`, `ws://127.0.0.1:*`)
- style-src keeps 'unsafe-inline' for React style={{…}}
- worker-src / img-src allow blob: and data: for pdfjs and attachments
- no remote connect, no unsafe-eval in production
- a separate, looser devCsp so `tauri dev` still gets Vite HMR on :1420

And drop `allow-same-origin` from the artifact iframe. Scripts can still run
for interactive previews; the frame gets a unique opaque origin, which is the
actual XSS → tools fix. Parent CSP alone cannot contain a srcDoc iframe.

Hermetic contract tests pin both: production/dev CSP shape, and the iframe
sandbox tokens. CI does not boot a Tauri webview, so these assertions are what
keeps the policy from regressing to null.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Security] Tauri CSP is disabled (csp: null) — XSS amplifies local API / tool access

1 participant