CodeVetter · Repo Unpack · Risk map
tauri-apps/tauri
The highest-stakes code is the IPC authorization boundary: invoke_key verification, ACL resolution, remote-origin rejection, and eval-based response delivery all sit on the webview↔Rust seam. The `asset:` protocol touches the filesystem and relies entirely on scope checks. The CLI executes config-supplied shell commands and writes a predictable-path kill script. Several cross-language invariants (serialization key names, `plugin:` command syntax, JNI symbol names, JS template placeholders) are maintained only by comments, and the workspace release profile aborts on panic.
- ACL gatekeeping in `Webview::on_message` is the central security boundary: plugin commands, apps with an ACL manifest, and any non-local origin all require a resolved ACL entry or the invoke is rejected — a regression here silently opens commands to remote content.
- invoke_key is generated per-process (128-bit Z85) and injected into init scripts; on mismatch `on_message` logs/eprintln and returns silently — no user-visible error, which can mask attacks or bugs.
- Responses are delivered by `webview.eval` of JS built by `format_callback`; any serialization gap there is an injection vector inside the webview context. (inferred)
- The `asset:` protocol opens arbitrary paths from the filesystem with only `SafePathBuf` validation and `scope.is_allowed`; it sniffs mime types and serves range requests — scope misconfiguration exposes host files to the webview.
- The ipc custom-protocol handler sets `Access-Control-Allow-Origin: *` on every response (and `Access-Control-Allow-Headers: *` on OPTIONS), relying on the invoke_key + ACL rather than origin restriction.
- `tauri dev` executes `build.beforeDevCommand`/`beforeBuildCommand` through `sh -c`/`cmd /S /C` — a shell-out of config-provided strings — and writes a fixed-name script `tauri-stop-dev-processes.sh` into the shared temp dir with mode 0o770.
- The Isolation pattern decrypts IPC payloads (`crypto_keys.decrypt`) inside `handle_ipc_message`/`parse_invoke_request`; its correctness depends on iframe-origin checks in scripts/isolation.js and codegen injecting `__TAURI_ISOLATION_HOOK__`, which panics the build if absent.
- Cross-language invariants are comment-enforced: `__TAURI_TO_IPC_KEY__` must match across core.ts, ipc.js and process-ipc-message-fn.js, and the Java `Java_app_tauri_plugin_PluginManager_handlePluginResponse` symbol is checked by the CLI — silent breakage risk on rename.
- `dynamic-acl` is a default feature enabling `Manager::add_capability` — runtime ACL mutation means permissions can broaden after startup, which complicates security review of an app built on this framework.
- Feature `process-relaunch-dangerous-allow-symlink-macos` is documented in lib.rs as dangerous; combined with `process::restart` in the exit path it is a self-reexec surface.
- Build-time panics: context_codegen `panic!`s when frontendDist doesn't exist or the isolation dir lacks `__TAURI_ISOLATION_HOOK__`, and `Resolved::resolve(...).expect("failed to resolve ACL")` aborts compilation — config errors surface as rustc panics, not diagnostics.
- Blast-radius hotspots: `crates/tauri-utils` config/ACL types are consumed by tauri, tauri-build, tauri-codegen, tauri-cli and tauri-plugin simultaneously — a schema change ripples through five crates plus generated schema files guarded by check-generated-files.yml. (inferred)
- The workspace release profile sets `panic = "abort"`, so any panic in a shipped app (including in plugin code or the asset protocol task spawns) terminates the process without unwind.