diff --git a/docs/architecture/09-security.md b/docs/architecture/09-security.md index b54309ca..ec4ec3ce 100644 --- a/docs/architecture/09-security.md +++ b/docs/architecture/09-security.md @@ -51,6 +51,66 @@ pub struct EncryptedFileStorage; // AES-256-GCM fallback | Token Transmission | Bearer token in `Authorization` header only | | Token Refresh | Handled by Jellyfin server (long-lived tokens) | +## Webview Content Security Policy + +`app.security.csp` in `tauri.conf.json` (TRACES: UR-012, UR-071 | DR-198). It was +`null` — CSP disabled — which meant any script that reached the web layer +inherited the full IPC surface. Tauri computes the header from this value when it +serves the embedded HTML, injecting a nonce for SvelteKit's inline bootstrap +script, so `script-src` needs no `'unsafe-inline'`. + +``` +default-src 'self'; +script-src 'self'; +style-src 'self' 'unsafe-inline'; +font-src 'self' data:; +img-src 'self' data: blob: asset: http://asset.localhost http: https:; +media-src 'self' blob: asset: http://asset.localhost http://127.0.0.1:* http: https:; +connect-src 'self' ipc: http://ipc.localhost http: https:; +worker-src 'self' blob:; +object-src 'none'; frame-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none' +``` + +| Directive | Why | +|-----------|-----| +| `default-src 'self'` | Everything not named below is same-origin only. | +| `script-src 'self'` | The genuinely restrictive half. Bundled JS only; Tauri's build-time nonce covers the one inline `