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.
This commit is contained in:
J3vb
2026-07-20 14:51:23 +02:00
parent 352b7c8cc1
commit 59ec405595
3 changed files with 10 additions and 3 deletions
+1
View File
@@ -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 |
+4 -1
View File
@@ -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
+5 -2
View File
@@ -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