From 59ec405595bf937eeb3ffdc2ea28fe1a369f9426 Mon Sep 17 00:00:00 2001 From: J3vb <192430104+J3vb@users.noreply.github.com> Date: Mon, 20 Jul 2026 14:51:23 +0200 Subject: [PATCH] docs: record final Tauri capability posture and residual risk Update the security doc's capability section with the deny list, the fact that `http:allow-fetch` is the only URL-scoped HTTP identifier, and why the https wildcard cannot be removed without moving the link-preview fetch into Rust. Note under Known Limitations that narrowing the plugin scope alone does not bound exfiltration while CSP `connect-src` allows `https:` to any host. Add a capability row to the client architecture doc and mark the design note implemented. --- docs/architecture/client.md | 1 + docs/plans/tauri-capability-narrowing.md | 5 ++++- docs/security.md | 7 +++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/architecture/client.md b/docs/architecture/client.md index 5fe67a6e..f3916e84 100644 --- a/docs/architecture/client.md +++ b/docs/architecture/client.md @@ -96,6 +96,7 @@ other (auth→voice→members), and the Solid beachhead is dead weight. | Cert trust | `src-tauri/src/ws_proxy.rs` | TOFU: first fingerprint pinned per host (`certs.json`); mismatch → modal (`CertMismatchModal`) | | Credentials | `src-tauri/src/credentials.rs` | OS keychain per host; password field `serde(skip)` so it never crosses IPC back to JS | | Multi-server | `src/lib/profiles.ts` | Server profiles w/ 15s health polling and auto-connect; one active connection, quick-switch replaces WS + tunnels | +| HTTP capability | `src-tauri/capabilities/default.json` | `http:allow-fetch` is the only URL-scoped identifier (the other two `fetch_*` commands take a validated `ResourceId`); allows `https://*` + `http://127.0.0.1:*`, denies https loopback. Wildcard is required by link previews — see [docs/plans/tauri-capability-narrowing.md](../plans/tauri-capability-narrowing.md) | | Updates | `src/lib/updater.ts` + `update_commands.rs` | Endpoint derived from the connected server URL, https-only, TLS pinned to TOFU fingerprint, minisign-verified | | Settings | `commands.rs` + `src/lib/preferences.ts` | Split persistence: Rust store (`settings.json`, key-allowlisted) *and* raw `localStorage` for UI prefs/themes | | Theming | `src/lib/themes.ts` + `styles/tokens.css` | CSS custom properties; 4 built-in themes + custom overrides | diff --git a/docs/plans/tauri-capability-narrowing.md b/docs/plans/tauri-capability-narrowing.md index b78cfff4..d7cc3b9c 100644 --- a/docs/plans/tauri-capability-narrowing.md +++ b/docs/plans/tauri-capability-narrowing.md @@ -1,6 +1,9 @@ # Tauri HTTP Capability Narrowing — Design -**Status:** design only (2026-07-20) — no code change in this PR +**Status:** implemented (2026-07-20) — the Decision below landed in +`Client/tauri-client/src-tauri/capabilities/default.json`, guarded by +`tests/unit/capabilities-scope.test.ts`. The follow-up at the end of this +document is still open. **Phase:** P3 "Client + plugin security parity" **Follows:** [http-tofu-proxy.md](http-tofu-proxy.md) (A-2026-07-02), which moved REST/health/attachment traffic onto a loopback origin and was expected to make diff --git a/docs/security.md b/docs/security.md index b54cfe7d..f64b75c9 100644 --- a/docs/security.md +++ b/docs/security.md @@ -51,7 +51,10 @@ The Tauri desktop client implements the following security measures: ### Tauri Capabilities (Least Privilege) - Filesystem write access is scoped to `$APPDATA/**` and `$APPLOG/**` only - DevTools command is gated behind the `devtools` feature flag (excluded from release builds) -- HTTP fetch permissions are restricted to `https://` origins +- HTTP fetch is restricted to `https://` origins plus `http://127.0.0.1:*` (the Rust TOFU proxy's loopback tunnel), and **denies** `https://localhost[:*]` and `https://127.0.0.1[:*]` — no legitimate flow reaches loopback over https, so the deny list keeps the renderer from probing other local services +- `http:allow-fetch` is the **only** URL-scoped HTTP identifier. `tauri-plugin-http` validates the URL exactly once, in the `fetch` command; `fetch_send` and `fetch_read_body` operate on an already-validated `ResourceId` and never consult a scope, so `allow`/`deny` blocks on those identifiers are inert and were removed rather than left in place advertising a control that does not exist +- The `https://*` wildcard cannot be removed today: link previews (`embeds.ts`) fetch arbitrary user-posted URLs by design, and Tauri scopes per *command*, not per JS caller. Bounded in TypeScript by `isPrivateHost`/`isBlockedForPreview`, a 5 s timeout and a 50 KB body cap; the response is regex-scraped for `og:` tags and never executed +- Regression-guarded by `tests/unit/capabilities-scope.test.ts`; rationale and the follow-up that would remove the wildcard are in [docs/plans/tauri-capability-narrowing.md](plans/tauri-capability-narrowing.md) ### TLS and Certificate Pinning (TOFU) - Self-signed certificates are supported via Trust-On-First-Use (TOFU) pinning @@ -85,7 +88,7 @@ The Tauri desktop client implements the following security measures: - Server auto-updates depend on a dedicated pinned minisign/Ed25519 server release key in [Server/updater/server_update_public_key.txt](Server/updater/server_update_public_key.txt) and a signed release manifest that binds the shipped binary hash to the release version; Windows Authenticode/SmartScreen code signing is still separate work - The Tenor API key is hardcoded (Google's public anonymous key) — consider build-time injection for production -- CSP `connect-src` allows `https:` to any host (necessary for self-hosted server URLs not known at build time) +- CSP `connect-src` allows `https:` to any host (necessary for self-hosted server URLs not known at build time). Because of this, narrowing the Tauri `http:allow-fetch` scope alone would not bound exfiltration from a compromised renderer — the webview's own `fetch` reaches the same hosts without going through the plugin. Closing that requires narrowing `connect-src` and moving the link-preview fetch into Rust in the same change ## Security Hardening Checklist for Operators